Repository: matthieu-m/ghost-collections Branch: master Commit: 4a72daed3758 Files: 15 Total size: 260.4 KB Directory structure: gitextract_xxgw4ag_/ ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src/ ├── lib.rs ├── linked_list/ │ ├── cursor.rs │ └── iter.rs ├── linked_list.rs ├── tripod_list/ │ ├── cursor.rs │ └── iter.rs ├── tripod_list.rs ├── tripod_tree/ │ ├── cursor.rs │ └── iter.rs └── tripod_tree.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .cargo target Cargo.lock ================================================ FILE: Cargo.toml ================================================ [package] name = "ghost-collections" version = "0.1.0" authors = ["Matthieu M. "] edition = "2018" description = "Safe collections, on stable Rust" repository = "https://github.com/matthieu-m/ghost-collections" license = "MIT OR Apache-2.0" keywords = ["experimental", "aliasing", "borrowing"] categories = ["data-structures", "no-std"] [dependencies] ghost-cell = "0.2" static-rc = { version = "0.4.0", features = ["experimental-lift"] } [features] # Enables a variety of features relying on the experimental ghost-cell `GhostCursor`, such as LinkedList's append and cursor_mut. experimental-ghost-cursor = ["ghost-cell/experimental-ghost-cursor"] # Enables debug printing to stderr, only available in test to debug trees. test-tree-debug = [] ================================================ FILE: LICENSE-APACHE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2020 matthieu-m Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: LICENSE-MIT ================================================ Copyright 2021 matthieu-m Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ A proof of concept implementation of cyclic data structures in stable, safe, Rust. This demonstrates the combined power of the [static-rc](https://github.com/matthieu-m/static-rc) crate and the [ghost-cell](https://github.com/matthieu-m/ghost-cell) crate. # Motivation ## Why the focus on safety? A simple combination of 2 facts about data structures: - They are pervasive and often used to store user-controlled input. - They are extremely error-prone, juggling lifetime and aliasing concerns at the same time. The combination of this two factors means that a single logical bug can result in Undefined Behavior, opening up the door to a multitude of attacks. ## How can you write safe cyclic data structures? There are typically two obstacles, as mentioned: lifetime, and aliasing. The state of the art recommendation today is one of: - A `Vec` with indices instead of pointers. - An arena to handle lifetime, and some form of cell to handle aliasing. - `Rc` + `RefCell`. ## What's wrong with those approaches? `Vec` based solutions will blow up the algorithmic complexity of splice/split operations. In a linked list, splicing in another list, or splitting a part of the list, are both O(1) operations, but transferring N elements from one `Vec` to another is at least an O(N) operation. Arena based solution will allow implementing all operations with their expected algorithmic complexity, but this comes at the cost of never being able to reclaim memory from the arena as long as a single data structure exists which references the arena. Finally `Rc` + `RefCell` suffer from increased memory consumption and runtime overhead: - `Rc` typically embeds 2 `usize` counters: the strong and weak count. - An `Rc` implementation optimized for data structures could ditch the weak count. - `RefCell` typically embeds an `isize` counter: to count the number of readers and writers. # Does ghost-collections offer a better alternative then? Maybe. ## Lighter-weight building bricks This crate aims at refining the `Rc` + `RefCell` solution by substituting both of them with `StaticRc` and `GhostCell` respectively: - `GhostCell` is a compile-time cell, splitting the aliasing compile-time checks to the zero-sized `GhostToken`. - `StaticRc` is a compile-time reference counted pointer, so is _mostly_ free at run-time. - One exception: joining 2 `StaticRc` requires checking that they both refer to the same allocation. On the face of it, this seems fairly interesting: - No memory overhead. - No run-time overhead. ## And a catch. There's a catch, though. `GhostCell` is a straightforward replacement, `StaticRc` is a _bit_ more complicated. Typical implementations based on `Rc` will clone it whenever necessary -- but cloning a `StaticRc` is impossible. If you have split your `StaticRc` in halves, that is, you have 2 instances of `StaticRc`, then you only have those two instances. You can split one, but it changes its type. This makes _temporarily_ holding onto one more instance of a reference-counted pointer... impossible. There's no temporary instance. To solve this problem, the nodes of the `TripodList` and `TripodTree` contain one extra instance of a pointer, compared to the typical implementation. That is, a node from a `TripodList` contains 3 pointers, and one from a `TripodTree` contains 4 pointers. That's the same memory overhead as a special-purpose `Rc` with no weak count. And mostly the same run-time overhead too as deploying the _tripod_ pointer is a memory write, just as cloning a `Rc`, and retracting the _tripod_ pointer is another memory write, just as destroying a `Rc`. It may be slightly more efficient, and linear logic keeps one honest... It _may_ be possible to avoid this overhead altogether. `LinkedList` avoids it... and uses the experimental `GhostCursor` instead. It's not clear whether `GhostCursor` is _quite_ sufficient to implement all the functionality of a list, though. And then there's the _experimental_ issue... ## At least it's safe, no? Mostly? The core functionality of `GhostCell` and `StaticRc` are really strong contenders: - `GhostCell` (the paper) was developed by Ralf Jung and co, and proven safe. The implementation hopefully is also safe. - `StaticRc` is really basic reference-counting, just at compile-time. The core functionality, though, is also _slightly_ insufficient. This forces this crate to use extra, experimental functionality from its 2 core crates, and those are much less proven: - `static_rc::lift*` is at the core of this crate. None of the collections are too useful without it. Its core idea _looks_ sound (scary eh?), though even if it is, the implementation may not be... - `GhostCursor` is even more sketchy, safety-wise. If safe, it may allow writing the collections without an extra _tripod_ pointer... May. # Is ghost-collections really helpful then? **Yes**. ## GhostCell is practical. At the very least, this crate is a proof-of-concept that `GhostCell` is _really_ usable. To the best of our knowledge, this is the first crate making extensive use of `GhostCell`, and there were some questions as to whether it was possible to express algorithms with `GhostCell`. Having implemented a complete linked list and binary tree around `GhostCell` I can confirm that it is **practical** enough. Replacing `RefCell` by `GhostCell` means avoiding both the memory and run-time overhead of `RefCell`. That's a significant advantage. There are some ergonomic downsides, though: - Using lifetime as a brand means that all the entire program needs to be wrapped within a closure. - Having to pass the extra `GhostToken` everywhere means that many traits -- such as `Debug` -- cannot be implemented on the collections. Those were all foreseen, so no surprise there, but of course it's still annoying. ## StaticRc is practical. This crate also proves that `StaticRc` works, although it is perhaps not the best tool for cyclic data structures. ## Test bed. Finally, this crate provides a test bed for both of the above. After putting them through their paces, I am happy to report that MIRI finds no issue when running the full test-suite. # And beyond? One interesting avenue of investigation is automatic translation of the current code, stripping out `StaticRc` and/or `GhostCell`. As long as: - The current code is safe -- meaning, the 2 crates used are safe. - The translation preserves safety. Then this opens up the ability to write entirely safe code and automatically translate it into simpler (though unsafe) code -- not unlike the work that compilers do. Exciting, isn't it? There is one difficulty, though, it's unclear whether the remove/split operations can be translated automatically: - Merging 2 pools of nodes -- through `splice` -- is trivially safe: the result is a coarser grain. - Splitting 1 pool of nodes into two, however, is not: the result is finer grain. Today, the reference-counting and borrowing works _globally_, regardless of which pools of nodes a node belongs to. However translating `StaticRc, N, D>` into just `NonNull` breaks this assumptions, and functional bugs such as accidentally keeping a link between nodes across pools could lead to aliasing/lifetime issues. _Note: and even though tracing could solve the issue, it would be linear in the number of elements to trace at best, so would not make sense algorithmically._ # That's all folks! And thanks for reading. ================================================ FILE: src/lib.rs ================================================ //! A repository of collections written entirely in safe, zero-cost, stable, Rust. //! //! # Safety //! //! This repository is built upon 2 crates: //! //! - `ghost-cell`: which provides safe borrow-checking of aliases, with zero runtime overhead. //! - `static-rc`: which provides safe reference-counting of aliases, with zero runtime overhead. //! //! Additionally, this repository builds upon the `core` and `alloc` crates. //! //! The safety of this library depends, entirely, and only, on the safety of those 4 foundational libraries. // Generic features. #![cfg_attr(not(test), no_std)] #![forbid(unsafe_code)] // Lints. #![deny(missing_docs)] pub mod linked_list; pub mod tripod_list; pub mod tripod_tree; ================================================ FILE: src/linked_list/cursor.rs ================================================ use ghost_cell::GhostToken; use super::{GhostNode, LinkedList}; #[cfg(feature = "experimental-ghost-cursor")] use ghost_cell::GhostCursor; #[cfg(feature = "experimental-ghost-cursor")] use super::Node; /// A Cursor over the LinkedList. pub struct Cursor<'a, 'brand, T> { token: &'a GhostToken<'brand>, node: Option<&'a GhostNode<'brand, T>>, } impl<'a, 'brand, T> Cursor<'a, 'brand, T> { /// Creates a new instance pointing to the front element of the list, if any. pub fn new_front(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0); Self { token, node, } } /// Creates a new instance pointing to the back element of the list, if any. pub fn new_back(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1); Self { token, node, } } /// Moves the cursor to the next element, if any. /// /// If there is no next element, either because the list is empty, or because the current element is the back /// element, then an error is returned. pub fn move_next(&mut self) -> Result<(), ()> { if let Some(node) = self.peek_next_node() { self.node = Some(node); Ok(()) } else { Err(()) } } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, either because the list is empty, or because the current element is the front /// element, then an error is returned. pub fn move_prev(&mut self) -> Result<(), ()> { if let Some(node) = self.peek_prev_node() { self.node = Some(node); Ok(()) } else { Err(()) } } /// Returns a reference to the current element, if any. /// /// Unless the list is empty, there should always be a current element. pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the next element, if any. pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) } /// Returns a reference to the next element, if any. pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) } // Internal: returns a reference to the next GhostNode. fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> { self.node?.borrow(self.token).next.as_ref().map(|n| &**n) } // Internal: returns a reference to the previous GhostNode. fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> { self.node?.borrow(self.token).prev.as_ref().map(|n| &**n) } } /// A mutable Cursor over a LinkedList. #[cfg(feature = "experimental-ghost-cursor")] pub struct CursorMut<'a, 'brand, T> { inner: GhostCursor<'a, 'brand, Node<'brand, T>>, } #[cfg(feature = "experimental-ghost-cursor")] impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Creates a new instance pointing to the front element of the list, if any. pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0); let inner = GhostCursor::new(token, node); Self { inner, } } /// Creates a new instance pointing to the back element of the list, if any. pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1); let inner = GhostCursor::new(token, node); Self { inner, } } /// Returns a read-only cursor pointing to the current element. pub fn into_cursor(self) -> Cursor<'a, 'brand, T> { let (token, node) = self.inner.into_parts(); Cursor { token, node, } } /// Moves the cursor to the next element, if any. /// /// If there is no next element, either because the list is empty, or because the current element is the back /// element, then an error is returned and the cursor is left unmodified. pub fn move_next(&mut self) -> Result<(), ()> { self.inner.move_mut(|node| node.next.as_ref().map(|n| &**n)) } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, either because the list is empty, or because the current element is the front /// element, then an error is returned and the cursor is left unmodified. pub fn move_prev(&mut self) -> Result<(), ()> { self.inner.move_mut(|node| node.prev.as_ref().map(|n| &**n)) } /// Returns a mutable reference to the current element, if any. /// /// Unless the list is empty, there should always be a current element. pub fn current(&mut self) -> Option<&mut T> { self.inner.borrow_mut().map(|node| &mut node.value) } /// Returns a reference to the next element, if any. /// /// # Deviation /// /// In safe code, it is not possible to allow mutable access to another node than the one currently visited as this /// other node could be the anchor of the current node to the stack. pub fn peek_next(&self) -> Option<&T> { let token = self.inner.token(); self.peek_next_node().map(|node| &node.borrow(token).value) } /// Returns a reference to the previous element, if any. /// /// # Deviation /// /// In safe code, it is not possible to allow mutable access to another node than the one currently visited as this /// other node could be the anchor of the current node to the stack. pub fn peek_prev(&self) -> Option<&T> { let token = self.inner.token(); self.peek_prev_node().map(|node| &node.borrow(token).value) } // Internal: returns a reference to the next GhostNode. fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> { self.inner.borrow().and_then(|node| node.next.as_ref().map(|n| &**n)) } // Internal: returns a reference to the previous GhostNode. fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> { self.inner.borrow().and_then(|node| node.prev.as_ref().map(|n| &**n)) } } #[cfg(test)] mod cursor_tests { use std::fmt::Debug; use super::super::tests::with_list; use super::*; #[track_caller] fn cursor_assert_none<'a, 'brand, T>(cursor: &Cursor<'a, 'brand, T>) where T: Debug + Eq, { assert_eq!(None, cursor.current()); assert_eq!(None, cursor.peek_next()); assert_eq!(None, cursor.peek_prev()); } #[test] fn cursor_brush_front_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = Cursor::new_front(token, list); cursor_assert_none(&cursor); assert_eq!(Err(()), cursor.move_next()); cursor_assert_none(&cursor); assert_eq!(Err(()), cursor.move_prev()); cursor_assert_none(&cursor); }); } #[test] fn cursor_brush_back_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = Cursor::new_back(token, list); cursor_assert_none(&cursor); assert_eq!(Err(()), cursor.move_next()); cursor_assert_none(&cursor); assert_eq!(Err(()), cursor.move_prev()); cursor_assert_none(&cursor); }); } #[test] fn cursor_brush_move_next() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut cursor = Cursor::new_front(token, list); assert_eq!(None, cursor.peek_prev().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(String::as_str)); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("1"), cursor.current().map(String::as_str)); assert_eq!(Some("2"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("2"), cursor.current().map(String::as_str)); assert_eq!(Some("3"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_next()); assert_eq!(Err(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_next()); assert_eq!(Err(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_next()); }); } #[test] fn cursor_brush_move_prev() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut cursor = Cursor::new_back(token, list); assert_eq!(None, cursor.peek_next().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(String::as_str)); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("3"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("2"), cursor.current().map(String::as_str)); assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("2"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("1"), cursor.current().map(String::as_str)); assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_prev()); assert_eq!(Err(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_prev()); assert_eq!(Err(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(String::as_str)); assert_eq!(None, cursor.peek_prev()); }); } } // mod cursor_tests #[cfg(all(test, feature = "experimental-ghost-cursor"))] mod cursor_mut_tests { use std::fmt::Debug; use super::super::tests::with_list; use super::*; #[track_caller] fn cursor_mut_assert_none<'a, 'brand, T>(cursor: &mut CursorMut<'a, 'brand, T>) where T: Debug + Eq, { assert_eq!(None, cursor.current()); assert_eq!(None, cursor.peek_next()); assert_eq!(None, cursor.peek_prev()); } #[test] fn cursor_mut_brush_front_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = CursorMut::new_front(token, list); cursor_mut_assert_none(&mut cursor); assert_eq!(Err(()), cursor.move_next()); cursor_mut_assert_none(&mut cursor); assert_eq!(Err(()), cursor.move_prev()); cursor_mut_assert_none(&mut cursor); }); } #[test] fn cursor_mut_brush_back_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = CursorMut::new_back(token, list); cursor_mut_assert_none(&mut cursor); assert_eq!(Err(()), cursor.move_next()); cursor_mut_assert_none(&mut cursor); assert_eq!(Err(()), cursor.move_prev()); cursor_mut_assert_none(&mut cursor); }); } #[test] fn cursor_mut_brush_move_next() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut cursor = CursorMut::new_front(token, list); assert_eq!(None, cursor.peek_prev().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(|s| &**s)); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("1"), cursor.current().map(|s| &**s)); assert_eq!(Some("2"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("2"), cursor.current().map(|s| &**s)); assert_eq!(Some("3"), cursor.peek_next().map(String::as_str)); assert_eq!(Ok(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_next()); assert_eq!(Err(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_next()); assert_eq!(Err(()), cursor.move_next()); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_next()); }); } #[test] fn cursor_mut_brush_move_prev() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut cursor = CursorMut::new_back(token, list); assert_eq!(None, cursor.peek_next().map(String::as_str)); assert_eq!(Some("3"), cursor.current().map(|s| &**s)); assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("3"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("2"), cursor.current().map(|s| &**s)); assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("2"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("1"), cursor.current().map(|s| &**s)); assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str)); assert_eq!(Ok(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_prev()); assert_eq!(Err(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_prev()); assert_eq!(Err(()), cursor.move_prev()); assert_eq!(Some("1"), cursor.peek_next().map(String::as_str)); assert_eq!(Some("0"), cursor.current().map(|s| &**s)); assert_eq!(None, cursor.peek_prev()); }); } } // mod cursor_mut_tests ================================================ FILE: src/linked_list/iter.rs ================================================ use ghost_cell::GhostToken; use super::{GhostNode, LinkedList}; /// An iterator over a LinkedList, self-sufficient once created as it carries its own token. pub struct Iter<'a, 'brand, T> { token: &'a GhostToken<'brand>, head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>, } impl<'a, 'brand, T> Iter<'a, 'brand, T> { /// Creates a new instance of the Iter. pub fn new(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self { let head_tail = list.head_tail.as_ref().map(|head_tail| { (&*head_tail.0, &*head_tail.1) }); Self { token, head_tail, } } } impl<'a, 'brand, T> Iterator for Iter<'a, 'brand, T> { type Item = &'a T; fn next(&mut self) -> Option { let (head, tail) = self.head_tail.take()?; let node = head.borrow(self.token); if head as *const _ != tail as *const _ { self.head_tail = node.next.as_ref().map(|n| { let n: &'a GhostNode<'_, _> = &*n; (n, tail) }); } else { self.head_tail = None; } Some(&node.value) } } impl<'a, 'brand, T> DoubleEndedIterator for Iter<'a, 'brand, T> { fn next_back(&mut self) -> Option { let (head, tail) = self.head_tail.take()?; let node = tail.borrow(self.token); if head as *const _ != tail as *const _ { self.head_tail = node.prev.as_ref().map(|n| { let n: &'a GhostNode<'_, _> = &*n; (head, n) }); } else { self.head_tail = None; } Some(&node.value) } } #[cfg(test)] mod tests { use super::super::tests::with_list; use super::*; #[test] fn empty() { with_list::(vec!(), |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(None, iterator.next()); assert_eq!(None, iterator.next_back()); }); } #[test] fn forward() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next().map(String::as_str)); assert_eq!(Some("3"), iterator.next().map(String::as_str)); assert_eq!(None, iterator.next()); }); } #[test] fn backward() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next_back().map(String::as_str)); assert_eq!(Some("0"), iterator.next_back().map(String::as_str)); assert_eq!(None, iterator.next_back()); }); } #[test] fn alternate() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(None, iterator.next()); assert_eq!(None, iterator.next_back()); }); } #[test] fn alternate_other() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(None, iterator.next_back()); assert_eq!(None, iterator.next()); }); } } // mod tests ================================================ FILE: src/linked_list.rs ================================================ //! A LinkedList, with externally supplied token. //! //! A number of operations normally implemented by traits cannot be successfully implemented on this collection due to //! the requirement of supplying the GhostToken externally. mod iter; mod cursor; pub use iter::Iter; pub use cursor::Cursor; #[cfg(feature = "experimental-ghost-cursor")] pub use cursor::CursorMut; use ghost_cell::{GhostCell, GhostToken}; use static_rc::StaticRc; #[cfg(feature = "experimental-ghost-cursor")] use core::mem; #[cfg(feature = "experimental-ghost-cursor")] use ghost_cell::GhostCursor; /// A safe implementation of a linked-list build upon `GhostCell` and `StaticRc`. /// /// The future is now! pub struct LinkedList<'brand, T> { head_tail: Option<(HalfNodePtr<'brand, T>, HalfNodePtr<'brand, T>)>, } impl<'brand, T> LinkedList<'brand, T> { /// Creates an empty list. pub const fn new() -> Self { Self { head_tail: None } } /// Creates an iterator over self. pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> { Iter::new(token, self) } /// Creates a cursor pointing to the front element, if any. pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_front(token, self) } /// Creates a cursor pointing to the back element, if any. pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_back(token, self) } /// Returns whether the list is empty, or not. pub fn is_empty(&self) -> bool { self.head_tail.is_none() } /// Returns the number of elements of the list. /// /// # Complexity /// /// This operation is O(N). /// /// Maintaining a separate length field is incompatible with arbitrary splits at a given cursor position. pub fn len(&self, token: &GhostToken<'brand>) -> usize { self.iter(token).count() } /// Clears the list, making it empty. /// /// # Complexity /// /// This operation is O(N), where N is the number of elements. pub fn clear(&mut self, token: &mut GhostToken<'brand>) { while let Some(_) = self.pop_back(token) {} } /// Returns a reference to the first element, if any. pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { self.head_tail.as_ref().map(|(head, _)| { &head.borrow(token).value }) } /// Returns a mutable reference to the first element, if any. pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { self.head_tail.as_mut().map(move |(head, _)| { &mut head.borrow_mut(token).value }) } /// Returns a reference to the last element, if any. pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { self.head_tail.as_ref().map(|(_, tail)| { &tail.borrow(token).value }) } /// Returns a mutable reference to the last element, if any. pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { self.head_tail.as_mut().map(move |(_, tail)| { &mut tail.borrow_mut(token).value }) } /// Prepends the given element at the front of the list. pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) { let (one, two) = Self::new_halves(value); let head_tail = if let Some((head, tail)) = self.head_tail.take() { head.borrow_mut(token).prev = Some(one); two.borrow_mut(token).next = Some(head); (two, tail) } else { (one, two) }; self.head_tail = Some(head_tail); } /// Removes and returns the first element of the list, if any. pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option { let (head, tail) = self.head_tail.take()?; if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) { return Some(Self::into_inner(head, tail)); } let next = head.borrow_mut(token).next.take() .expect("Non-tail should have a next node"); let other_head = next.borrow_mut(token).prev.take() .expect("Non-head should have a previous node"); self.head_tail = Some((next, tail)); Some(Self::into_inner(head, other_head)) } /// Appends the given element at the back of the list. pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) { let (one, two) = Self::new_halves(value); let head_tail = if let Some((head, tail)) = self.head_tail.take() { tail.borrow_mut(token).next = Some(one); two.borrow_mut(token).prev = Some(tail); (head, two) } else { (one, two) }; self.head_tail = Some(head_tail); } /// Removes and returns the last element of the list, if any. pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option { let (head, tail) = self.head_tail.take()?; if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) { return Some(Self::into_inner(head, tail)); } let prev = tail.borrow_mut(token).prev.take() .expect("Non-head should have a previous node"); let other_tail = prev.borrow_mut(token).next.take() .expect("Non-tail should have a next node"); self.head_tail = Some((head, prev)); Some(Self::into_inner(tail, other_tail)) } fn new_halves(value: T) -> (HalfNodePtr<'brand, T>, HalfNodePtr<'brand, T>) { let node = Node { value, prev: None, next: None, }; let full = FullNodePtr::new(GhostNode::new(node)); StaticRc::split::<1, 1>(full) } fn into_inner(left: HalfNodePtr<'brand, T>, right: HalfNodePtr<'brand, T>) -> T { let full = FullNodePtr::join(left, right); let ghost_cell = FullNodePtr::into_inner(full); let node = GhostNode::into_inner(ghost_cell); // If the node still has a prev and next, they are leaked. debug_assert!(node.prev.is_none()); debug_assert!(node.next.is_none()); node.value } } #[cfg(feature = "experimental-ghost-cursor")] impl<'brand, T> LinkedList<'brand, T> { /// Appends all elements of `other`, in order, to the back of this list. /// /// After this call, `other` is empty /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) { let other_ht = if let Some(other_ht) = other.head_tail.take() { other_ht } else { return; }; if let Some(self_ht) = self.head_tail.take() { let (new_head, mid_tail) = self_ht; let (mid_head, new_tail) = other_ht; mid_tail.borrow_mut(token).next = Some(mid_head); let previous = static_rc::lift_with_mut(Some(mid_tail), token, |mid_tail: &Option>, token| { let mut cursor = GhostCursor::new(token, Some(mid_tail.as_ref().unwrap())); cursor.move_mut(|mid_tail| mid_tail.next.as_ref().map(core::borrow::Borrow::borrow)) .expect("mid_tail.next was just set!"); let mid_head = cursor.into_inner().expect("mid_head was just computed!"); &mut mid_head.prev }); debug_assert!(previous.is_none(), "mid_head should not have had any previous!"); self.head_tail = Some((new_head, new_tail)); } else { self.head_tail = Some(other_ht); } } /// Prepends all elements of `other`, in order, to the front of this list. /// /// After this call, `other` is empty /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) { other.append(self, token); mem::swap(self, other); } /// Creates a cursor pointing to the front element, if any. pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_front(token, self) } /// Creates a cursor pointing to the back element, if any. pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_back(token, self) } /// Splits the list in two at the given index. Returns a list containing everything after the given index, inclusive. /// /// Returns None if the given index is out of bounds. /// /// # Complexity /// /// This operations is O(min(`at`, N)), where N is the number of elements. /// /// No memory allocation or deallocation occurs. pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Option { // This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity. let mut head = LinkedList::new(); for _ in 0..at { let element = if let Some(element) = self.pop_front(token) { element } else { // Restore popped elements, and pretend that nothing happened. self.prepend(&mut head, token); return None; }; head.push_back(element, token); } mem::swap(self, &mut head); Some(head) } /// Removes the element at the given index, and returns it, if the index is within bounds. /// /// # Complexity /// /// This operations is O(min(`at`, N)), where N is the number of elements. /// /// No memory allocation occurs, and a single memory deallocation occurs. pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Option { // This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity. let mut head = LinkedList::new(); for _ in 0..at { let element = if let Some(element) = self.pop_front(token) { element } else { // Restore popped elements, and pretend that nothing happened. self.prepend(&mut head, token); return None; }; head.push_back(element, token); } let result = self.pop_front(token); // Restore popped elements! self.prepend(&mut head, token); result } } impl<'brand, T> Default for LinkedList<'brand, T> { fn default() -> Self { Self::new() } } // // Implementation // struct Node<'brand, T> { value: T, prev: Option>, next: Option>, } type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>; type HalfNodePtr<'brand, T> = StaticRc, 1, 2>; type FullNodePtr<'brand, T> = StaticRc, 2, 2>; #[cfg(test)] mod tests { use std::panic::{self, AssertUnwindSafe}; use super::*; pub(crate) fn with_list(initial: Vec, fun: F) -> R where F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut LinkedList<'brand, T>) -> R, { GhostToken::new(|mut token| { let mut list = LinkedList::new(); for value in initial { list.push_back(value, &mut token); } let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut list))); list.clear(&mut token); result.expect("No Panic") }) } } // mod tests ================================================ FILE: src/tripod_list/cursor.rs ================================================ use core::mem; use ghost_cell::GhostToken; use super::{GhostNode, Iter, ThirdNodePtr, TripodList}; /// A Cursor over the TripodList. pub struct Cursor<'a, 'brand, T> { token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>, node: Option<&'a GhostNode<'brand, T>>, index: usize, } impl<'a, 'brand, T> Cursor<'a, 'brand, T> { /// Creates a new instance pointing to the front element of the list, if any. pub fn new_front(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0); Self { token, index: 0, node, list, } } /// Creates a new instance pointing to the back element of the list, if any. pub fn new_back(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1); let index = list.len().checked_sub(1).unwrap_or(0); Self { token, index, node, list, } } /// Returns a triplet (iterator, iterator) in which: /// /// - The first iterator is an iterator over all the elements before the cursor. /// - The second iterator is an iterator over all the elements after the cursor. /// /// If the cursor currently points to the "twilight" non-element, all elements are considered to be before it. pub fn before_after(&self) -> (Iter<'a, 'brand, T>, Iter<'a, 'brand, T>) { if let Some(_) = self.node { let (head, tail) = self.list.head_tail.as_ref().expect("non-empty, node being non-null"); let prev = self.peek_prev_node(); let next = self.peek_next_node(); let before = prev.map(|prev| (&**head, prev)); let after = next.map(|next| (next, &**tail)); (Iter::slice(self.token, before), Iter::slice(self.token, after)) } else { (self.list.iter(self.token), Iter::empty(self.token)) } } /// Returns the index of the element pointed to by the cursor in the list. /// /// If the cursor currently points to the "twilight" non-element, returns None. pub fn index(&self) -> Option { self.node.map(|_| self.index) } /// Moves the cursor to the next element, if any. /// /// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. pub fn move_next(&mut self) { if self.node.is_some() { self.index += 1; } else { self.index = 0; } self.node = self.peek_next_node(); } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. pub fn move_prev(&mut self) { if self.node.is_some() { self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); } else { self.index = self.list.len().checked_sub(1).unwrap_or(0); } self.node = self.peek_prev_node(); } /// Returns a reference to the current element, if any. pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the next element, if any. pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) } /// Returns a reference to the previous element, if any. pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) } // Internal: returns a reference to the next GhostNode. fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> { if let Some(node) = self.node { node.borrow(self.token).next.as_ref().map(|n| &**n) } else { self.list.front_node() } } // Internal: returns a reference to the previous GhostNode. fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> { if let Some(node) = self.node { node.borrow(self.token).prev.as_ref().map(|n| &**n) } else { self.list.back_node() } } } impl<'a, 'brand, T> Clone for Cursor<'a, 'brand, T> { fn clone(&self) -> Self { *self } } impl<'a, 'brand, T> Copy for Cursor<'a, 'brand, T> {} /// A mutable cursor over the TripodList. /// /// A mutable cursor allows freely moving back-and-forth amongst the elements of the list, and mutate the list as any /// point. /// /// Cursors index the list in a logically circular way. To accomodate this, there is a "twilight" non-element /// represented by `None` between the head and tail of the list. /// /// # Warning. /// /// This cursor mutates the list as it iterates. Although the list is left in a safe state by construction, forgoing the /// drop of this cursor -- unless it points to the "twilight" non-element -- will leave the list in an unusable state. /// /// Any further mutable operation on the list, including calling `clear`, is at risk of panicking. pub struct CursorMut<'a, 'brand, T> { token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, T>, node: Option>, index: usize, } impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Creates a new instance pointing to the front element of the list, if any. pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| head_tail.0.borrow(token).deploy()); Self { token, index: 0, node, list, } } /// Creates a new instance pointing to the back element of the list, if any. pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, T>) -> Self { let node = list.head_tail.as_ref().map(|head_tail| head_tail.1.borrow(token).deploy()); let index = list.len().checked_sub(1).unwrap_or(0); Self { token, index, node, list, } } /// Returns a read-only cursor pointing to the current element. pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> { let token = &*self.token; let index = self.index; let node = self.node.as_ref().map(|rc| &**rc); let list = &*self.list; Cursor { token, index, node, list, } } /// Returns the index of the element pointed to by the cursor in the list. /// /// If the cursor currently points to the "twilight" non-element, returns None. pub fn index(&self) -> Option { self.node.as_ref().map(|_| self.index) } /// Moves the cursor to the next element, if any. /// /// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. pub fn move_next(&mut self) { let new_tripod = self.peek_next_node().map(|node| node.borrow(self.token).deploy()); if let Some(tripod) = mem::replace(&mut self.node, new_tripod) { super::retract(tripod, self.token); self.index += 1; } else { self.index = 0; } } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. pub fn move_prev(&mut self) { let new_tripod = self.peek_prev_node().map(|node| node.borrow(self.token).deploy()); if let Some(tripod) = mem::replace(&mut self.node, new_tripod) { super::retract(tripod, self.token); self.index = self.index.checked_sub(1).unwrap_or(0); } else { self.index = self.list.len().checked_sub(1).unwrap_or(0); } } /// Returns a mutable reference to the current element, if any. pub fn current(&mut self) -> Option<&mut T> { let tripod = self.node.as_ref()?; Some(&mut tripod.borrow_mut(self.token).value) } /// Returns a reference to the next element, if any. /// /// # Deviation /// /// It is not possible to return a mutable reference, safely. pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) } /// Returns a reference to the previous element, if any. /// /// # Deviation /// /// It is not possible to return a mutable reference, safely. pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) } // Internal: returns a reference to the next GhostNode. fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> { if let Some(node) = self.node.as_ref() { node.borrow(self.token).next.as_ref().map(|n| &**n) } else { self.list.front_node() } } // Internal: returns a reference to the previous GhostNode. fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> { if let Some(node) = self.node.as_ref() { node.borrow(self.token).prev.as_ref().map(|n| &**n) } else { self.list.back_node() } } } impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Inserts a new element in the list after the current one. /// /// If the cursor is pointing at the "twilight" non-element, then the new element is inserted at the front of the /// list. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// One memory allocation and no deallocation occur. pub fn insert_after(&mut self, item: T) { let mut list = TripodList::new(); list.push_front(item, self.token); self.splice_after(&mut list); debug_assert!(list.is_empty()); } /// Inserts a new element in the list before the current one. /// /// If the cursor is pointing at the "twilight" non-element, then the new element is inserted at the back of the /// list. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// One memory allocation and no deallocation occur. pub fn insert_before(&mut self, item: T) { let mut list = TripodList::new(); list.push_back(item, self.token); self.splice_before(&mut list); debug_assert!(list.is_empty()); } /// Removes the current element from the list, and return it. /// /// If the cursor is pointing to the "twilight" non-element, then None is returned and the cursor is left unmodified. /// Otherwise, the element is returned and the cursor is moved to the next element. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn remove_current(&mut self) -> Option { let mut list = self.remove_current_as_list()?; debug_assert_eq!(1, list.len()); list.pop_front(self.token) } /// Removes the current element from the list, and return it as a list of its own. /// /// If the cursor is pointing to the "twilight" non-element, then None is returned and the cursor is left unmodified. /// Otherwise, the element is returned and the cursor is moved to the next element. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn remove_current_as_list(&mut self) -> Option> { let node = self.node.take()?; let (head, tail) = self.list.head_tail.take()?; let prev = node.borrow_mut(self.token).prev.take(); let next = node.borrow_mut(self.token).next.take(); let (new_head_tail, result_head_tail, next_node) = match (prev, next) { // `node` is in the middle of the list, gotta splice the two bits together. (Some(prev), Some(next)) => { let next_node = next.borrow(self.token).deploy(); let result_head = prev.borrow_mut(self.token).next.replace(next).expect("node.prev.next == node"); let result_tail = next_node.borrow_mut(self.token).prev.replace(prev).expect("node.next.prev == node"); (Some((head, tail)), Some((result_head, result_tail)), Some(next_node)) }, // `node` is the current head of the list. (None, Some(next)) => { let next_node = next.borrow(self.token).deploy(); let result_tail = next.borrow_mut(self.token).prev.take().expect("node.next.prev == node"); (Some((next, tail)), Some((head, result_tail)), Some(next_node)) }, // `node` is the current tail of the list. (Some(prev), None) => { let result_head = prev.borrow_mut(self.token).next.take().expect("node.prev.next == node"); (Some((head, prev)), Some((result_head, tail)), None) }, // `node` is the only element of the list. (None, None) => { (None, Some((head, tail)), None) } }; super::retract(node, self.token); self.node = next_node; self.list.length -= 1; self.list.head_tail = new_head_tail; Some(TripodList { length: 1, head_tail: result_head_tail }) } /// Inserts the elements from the given list after the current one. /// /// If the cursor is pointing at the "twilight" non-element, then the new elements are inserted at the front of the /// list. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn splice_after(&mut self, other: &mut TripodList<'brand, T>) { if let Some(node) = self.node.as_ref() { let (other_head, other_tail) = if let Some(other_ht) = other.head_tail.take() { other_ht } else { return; }; let other_head_tripod = other_head.borrow(self.token).deploy(); if let Some(previous_next) = node.borrow_mut(self.token).next.replace(other_head) { let previous_next_tripod = previous_next.borrow(self.token).deploy(); other_tail.borrow_mut(self.token).next = Some(previous_next); let previous_node = previous_next_tripod.borrow_mut(self.token).prev.replace(other_tail); super::retract(previous_next_tripod, self.token); debug_assert!(previous_node.is_some(), "node.next.prev == node"); other_head_tripod.borrow_mut(self.token).prev = previous_node; super::retract(other_head_tripod, self.token); } else { let (head, tail) = self.list.head_tail.take().expect("Non-empty since self.node is non-null!"); other_head_tripod.borrow_mut(self.token).prev = Some(tail); super::retract(other_head_tripod, self.token); self.list.head_tail = Some((head, other_tail)); } self.list.length += other.length; other.length = 0; } else { self.list.prepend(other, self.token); } } /// Inserts the elements from the given list before the current one. /// /// If the cursor is pointing at the "twilight" non-element, then the new elements are inserted at the back of the /// list. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn splice_before(&mut self, other: &mut TripodList<'brand, T>) { if let Some(node) = self.node.as_ref() { let (other_head, other_tail) = if let Some(other_ht) = other.head_tail.take() { other_ht } else { return; }; let other_tail_tripod = other_tail.borrow(self.token).deploy(); if let Some(previous_prev) = node.borrow_mut(self.token).prev.replace(other_tail) { let previous_prev_tripod = previous_prev.borrow(self.token).deploy(); other_head.borrow_mut(self.token).prev = Some(previous_prev); let previous_node = previous_prev_tripod.borrow_mut(self.token).next.replace(other_head); super::retract(previous_prev_tripod, self.token); debug_assert!(previous_node.is_some(), "node.prev.next == node"); other_tail_tripod.borrow_mut(self.token).next = previous_node; super::retract(other_tail_tripod, self.token); } else { let (head, tail) = self.list.head_tail.take().expect("Non-empty since self.node is non-null!"); other_tail_tripod.borrow_mut(self.token).next = Some(head); super::retract(other_tail_tripod, self.token); self.list.head_tail = Some((other_head, tail)); } self.list.length += other.length; self.index += other.length; other.length = 0; } else { self.list.append(other, self.token); } } /// Splits the list into two after the current element. /// /// If the cursor is pointing at the "twilight" non-element, then the entire contents of the list are moved. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn split_after(&mut self) -> TripodList<'brand, T> { if let Some(node) = &self.node { let next = node.borrow_mut(self.token).next.take(); // node is not the tail of the current list. if let Some(next) = next { let (head, tail) = self.list.head_tail.take().expect("non-empty, node is non-null!"); let new_tail = next.borrow_mut(self.token).prev.take().expect("node.next.prev == node"); let remaining_length = self.index + 1; let result_length = self.list.length - remaining_length; self.list.length = remaining_length; self.list.head_tail = Some((head, new_tail)); TripodList { length: result_length, head_tail: Some((next, tail)) } } else { TripodList::new() } } else { mem::replace(self.list, TripodList::new()) } } /// Splits the list into two before the current element. /// /// If the cursor is pointing at the "twilight" non-element, then the entire contents of the list are moved. /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn split_before(&mut self) -> TripodList<'brand, T> { if let Some(node) = &self.node { let prev = node.borrow_mut(self.token).prev.take(); // node is not the head of the current list. if let Some(prev) = prev { let (head, tail) = self.list.head_tail.take().expect("non-empty, node is non-null!"); let new_head = prev.borrow_mut(self.token).next.take().expect("node.prev.next == node"); let result_length = self.index; let remaining_length = self.list.length - result_length; self.index = 0; self.list.length = remaining_length; self.list.head_tail = Some((new_head, tail)); TripodList { length: result_length, head_tail: Some((head, prev)) } } else { TripodList::new() } } else { mem::replace(self.list, TripodList::new()) } } } impl<'a, 'brand, T> Drop for CursorMut<'a, 'brand, T> { fn drop(&mut self) { if let Some(tripod) = self.node.take() { super::retract(tripod, self.token); } } } #[cfg(test)] mod tests { use std::fmt::Debug; use super::super::tests::*; use super::*; #[track_caller] fn assert_none<'a, 'brand, T>(cursor: Cursor<'a, 'brand, T>) where T: Debug + Eq, { assert_eq!(None, cursor.index()); assert_eq!(None, cursor.current()); assert_eq!(None, cursor.peek_next()); assert_eq!(None, cursor.peek_prev()); } #[track_caller] fn assert_cursor(before: &[&str], current: &str, after: &[&str], cursor: Cursor<'_, '_, String>) { assert_eq!(Some(before.len()), cursor.index()); assert_eq!(before.last().copied(), cursor.peek_prev().map(String::as_str)); assert_eq!(Some(current), cursor.current().map(String::as_str)); assert_eq!(after.first().copied(), cursor.peek_next().map(String::as_str)); let (actual_before, actual_after) = cursor.before_after(); assert_eq!(before, collect(actual_before)); assert_eq!(after, collect(actual_after)); } #[track_caller] fn assert_twilight(before: &[&str], cursor: Cursor<'_, '_, String>) { assert_eq!(None, cursor.index()); assert_eq!(before.last().copied(), cursor.peek_prev().map(String::as_str)); assert_eq!(None, cursor.current().map(String::as_str)); assert_eq!(before.first().copied(), cursor.peek_next().map(String::as_str)); let (actual_before, actual_after) = cursor.before_after(); let (actual_before, actual_after) = (collect(actual_before), collect(actual_after)); assert_eq!(before, actual_before); assert!(actual_after.is_empty(), "{:?}", actual_after); } // Creates a cursor at the specified index. fn place_cursor<'a, 'brand>(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, String>, at: usize) -> CursorMut<'a, 'brand, String> { assert!(at <= list.len()); let mut cursor = CursorMut::new_front(token, list); for _ in 0..at { cursor.move_next(); } cursor } #[test] fn cursor_front_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = Cursor::new_front(token, list); assert_none(cursor); cursor.move_next(); assert_none(cursor); cursor.move_prev(); assert_none(cursor); }); } #[test] fn cursor_back_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = Cursor::new_back(token, list); assert_none(cursor); cursor.move_next(); assert_none(cursor); cursor.move_prev(); assert_none(cursor); }); } #[test] fn cursor_move_next() { with_list(create(0..4), |token, list| { let mut cursor = Cursor::new_front(token, list); assert_cursor(&[], "0", &["1", "2", "3"], cursor); cursor.move_next(); assert_cursor(&["0"], "1", &["2", "3"], cursor); cursor.move_next(); assert_cursor(&["0", "1"], "2", &["3"], cursor); cursor.move_next(); assert_cursor(&["0", "1", "2"], "3", &[], cursor); cursor.move_next(); assert_twilight(&["0", "1", "2", "3"], cursor); cursor.move_next(); assert_cursor(&[], "0", &["1", "2", "3"], cursor); }); } #[test] fn cursor_move_prev() { with_list(create(0..4), |token, list| { let mut cursor = Cursor::new_back(token, list); assert_cursor(&["0", "1", "2"], "3", &[], cursor); cursor.move_prev(); assert_cursor(&["0", "1"], "2", &["3"], cursor); cursor.move_prev(); assert_cursor(&["0"], "1", &["2", "3"], cursor); cursor.move_prev(); assert_cursor(&[], "0", &["1", "2", "3"], cursor); cursor.move_prev(); assert_twilight(&["0", "1", "2", "3"], cursor); cursor.move_prev(); assert_cursor(&["0", "1", "2"], "3", &[], cursor); }); } #[test] fn cursor_mut_front_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = CursorMut::new_front(token, list); assert_none(cursor.as_cursor()); cursor.move_next(); assert_none(cursor.as_cursor()); cursor.move_prev(); assert_none(cursor.as_cursor()); }); } #[test] fn cursor_mut_back_empty() { // Test all functions on empty list. with_list::(vec!(), |token, list| { let mut cursor = CursorMut::new_back(token, list); assert_none(cursor.as_cursor()); cursor.move_next(); assert_none(cursor.as_cursor()); cursor.move_prev(); assert_none(cursor.as_cursor()); }); } #[test] fn cursor_mut_move_next() { with_list(create(0..4), |token, list| { let mut cursor = CursorMut::new_front(token, list); assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor()); cursor.move_next(); assert_cursor(&["0"], "1", &["2", "3"], cursor.as_cursor()); cursor.move_next(); assert_cursor(&["0", "1"], "2", &["3"], cursor.as_cursor()); cursor.move_next(); assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor()); cursor.move_next(); assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor()); cursor.move_next(); assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor()); }); } #[test] fn cursor_mut_move_prev() { with_list(create(0..4), |token, list| { let mut cursor = CursorMut::new_back(token, list); assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor()); cursor.move_prev(); assert_cursor(&["0", "1"], "2", &["3"], cursor.as_cursor()); cursor.move_prev(); assert_cursor(&["0"], "1", &["2", "3"], cursor.as_cursor()); cursor.move_prev(); assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor()); cursor.move_prev(); assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor()); cursor.move_prev(); assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor()); }); } #[track_caller] fn assert_insert_after(list: Vec, element: String, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); cursor.insert_after(element); assert_cursor(before, current, after, cursor.as_cursor()); }); } #[test] fn cursor_mut_insert_after() { assert_insert_after(create(0..4), "4".to_string(), 0, &[], "0", &["4", "1", "2", "3"]); assert_insert_after(create(0..4), "4".to_string(), 1, &["0"], "1", &["4", "2", "3"]); assert_insert_after(create(0..4), "4".to_string(), 2, &["0", "1"], "2", &["4", "3"]); assert_insert_after(create(0..4), "4".to_string(), 3, &["0", "1", "2"], "3", &["4"]); // Special case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); cursor.insert_after("4".to_string()); assert_twilight(&["4"], cursor.as_cursor()); }); // Special case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); cursor.insert_after("4".to_string()); assert_twilight(&["4", "0", "1", "2", "3"], cursor.as_cursor()); }); } #[track_caller] fn assert_insert_before(list: Vec, element: String, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); cursor.insert_before(element); assert_cursor(before, current, after, cursor.as_cursor()); }); } #[test] fn cursor_mut_insert_before() { assert_insert_before(create(0..4), "4".to_string(), 0, &["4"], "0", &["1", "2", "3"]); assert_insert_before(create(0..4), "4".to_string(), 1, &["0", "4"], "1", &["2", "3"]); assert_insert_before(create(0..4), "4".to_string(), 2, &["0", "1", "4"], "2", &["3"]); assert_insert_before(create(0..4), "4".to_string(), 3, &["0", "1", "2", "4"], "3", &[]); // Special case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); cursor.insert_before("4".to_string()); assert_twilight(&["4"], cursor.as_cursor()); }); // Special case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); cursor.insert_before("4".to_string()); assert_twilight(&["0", "1", "2", "3", "4"], cursor.as_cursor()); }); } #[track_caller] fn assert_splice_after(list: Vec, other: Vec, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list_duo(list, other, |token, list, other| { let mut cursor = place_cursor(token, list, at); cursor.splice_after(other); assert!(other.is_empty(), "{} elements!", other.len()); assert_cursor(before, current, after, cursor.as_cursor()); }); } #[track_caller] fn assert_splice_after_twilight(list: Vec, other: Vec, before: &[&str]) { with_list_duo(list, other, |token, list, other| { let mut cursor = place_cursor(token, list, list.len()); cursor.splice_after(other); assert!(other.is_empty(), "{} elements!", other.len()); assert_twilight(before, cursor.as_cursor()); }); } #[test] fn cursor_mut_splice_after() { // Empty spliced { assert_splice_after(create(0..4), create(0..0), 0, &[], "0", &["1", "2", "3"]); assert_splice_after(create(0..4), create(0..0), 1, &["0"], "1", &["2", "3"]); assert_splice_after(create(0..4), create(0..0), 2, &["0", "1"], "2", &["3"]); assert_splice_after(create(0..4), create(0..0), 3, &["0", "1", "2"], "3", &[]); // Special case: "empty" assert_splice_after_twilight(create(0..0), create(0..0), &[]); // Special case: "twilight" assert_splice_after_twilight(create(0..4), create(0..0), &["0", "1", "2", "3"]); } // Single-element spliced // See insert_after. // Multi-elements spliced { assert_splice_after(create(0..4), create(4..7), 0, &[], "0", &["4", "5", "6", "1", "2", "3"]); assert_splice_after(create(0..4), create(4..7), 1, &["0"], "1", &["4", "5", "6", "2", "3"]); assert_splice_after(create(0..4), create(4..7), 2, &["0", "1"], "2", &["4", "5", "6", "3"]); assert_splice_after(create(0..4), create(4..7), 3, &["0", "1", "2"], "3", &["4", "5", "6"]); // Special case: "empty" assert_splice_after_twilight(create(0..0), create(4..7), &["4", "5", "6"]); // Special case: "twilight" assert_splice_after_twilight(create(0..4), create(4..7), &["4", "5", "6", "0", "1", "2", "3"]); } } #[track_caller] fn assert_splice_before(list: Vec, other: Vec, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list_duo(list, other, |token, list, other| { let mut cursor = place_cursor(token, list, at); cursor.splice_before(other); assert!(other.is_empty(), "{} elements!", other.len()); assert_cursor(before, current, after, cursor.as_cursor()); }); } #[track_caller] fn assert_splice_before_twilight(list: Vec, other: Vec, before: &[&str]) { with_list_duo(list, other, |token, list, other| { let mut cursor = place_cursor(token, list, list.len()); cursor.splice_before(other); assert!(other.is_empty(), "{} elements!", other.len()); assert_twilight(before, cursor.as_cursor()); }); } #[test] fn cursor_mut_splice_before() { // Empty spliced { assert_splice_before(create(0..4), create(0..0), 0, &[], "0", &["1", "2", "3"]); assert_splice_before(create(0..4), create(0..0), 1, &["0"], "1", &["2", "3"]); assert_splice_before(create(0..4), create(0..0), 2, &["0", "1"], "2", &["3"]); assert_splice_before(create(0..4), create(0..0), 3, &["0", "1", "2"], "3", &[]); // Special case: "empty" assert_splice_before_twilight(create(0..0), create(0..0), &[]); // Special case: "twilight" assert_splice_before_twilight(create(0..4), create(0..0), &["0", "1", "2", "3"]); } // Single-element spliced // See insert_after. // Multi-elements spliced { assert_splice_before(create(0..4), create(4..7), 0, &["4", "5", "6"], "0", &["1", "2", "3"]); assert_splice_before(create(0..4), create(4..7), 1, &["0", "4", "5", "6"], "1", &["2", "3"]); assert_splice_before(create(0..4), create(4..7), 2, &["0", "1", "4", "5", "6"], "2", &["3"]); assert_splice_before(create(0..4), create(4..7), 3, &["0", "1", "2", "4", "5", "6"], "3", &[]); // Special case: "empty" assert_splice_before_twilight(create(0..0), create(4..7), &["4", "5", "6"]); // Special case: "twilight" assert_splice_before_twilight(create(0..4), create(4..7), &["0", "1", "2", "3", "4", "5", "6"]); } } #[track_caller] fn assert_remove_current(list: Vec, at: usize, result: Option<&str>, before: &[&str], current: &str, after: &[&str]) { with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); let actual = cursor.remove_current(); assert_eq!(result, actual.as_ref().map(String::as_str)); assert_cursor(before, current, after, cursor.as_cursor()); }); } #[test] fn cursor_mut_remove_current() { assert_remove_current(create(0..4), 0, Some("0"), &[], "1", &["2", "3"]); assert_remove_current(create(0..4), 1, Some("1"), &["0"], "2", &["3"]); assert_remove_current(create(0..4), 2, Some("2"), &["0", "1"], "3", &[]); // Special-case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); let actual = cursor.remove_current(); assert_eq!(None, actual); assert_twilight(&[], cursor.as_cursor()); }); // Special-case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); let actual = cursor.remove_current(); assert_eq!(None, actual); assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor()); }); // Special-case: "next twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 3); let actual = cursor.remove_current(); assert_eq!(Some("3"), actual.as_ref().map(String::as_str)); assert_twilight(&["0", "1", "2"], cursor.as_cursor()); }); } #[track_caller] fn assert_remove_current_as_list(list: Vec, at: usize, result: Option<&str>, before: &[&str], current: &str, after: &[&str]) { let result: Vec<_> = result.iter().copied().collect(); with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); let actual = cursor.remove_current_as_list(); assert_cursor(before, current, after, cursor.as_cursor()); mem::drop(cursor); assert_list(&result, token, actual.expect("Some")); }); } #[test] fn cursor_mut_remove_current_as_list() { assert_remove_current_as_list(create(0..4), 0, Some("0"), &[], "1", &["2", "3"]); assert_remove_current_as_list(create(0..4), 1, Some("1"), &["0"], "2", &["3"]); assert_remove_current_as_list(create(0..4), 2, Some("2"), &["0", "1"], "3", &[]); // Special-case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); let actual = cursor.remove_current_as_list(); assert!(actual.is_none()); assert_twilight(&[], cursor.as_cursor()); }); // Special-case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); let actual = cursor.remove_current_as_list(); assert!(actual.is_none()); assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor()); }); // Special-case: "next twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 3); let actual = cursor.remove_current_as_list(); assert_twilight(&["0", "1", "2"], cursor.as_cursor()); mem::drop(cursor); assert_list(&["3"], token, actual.expect("Some")); }); } #[track_caller] fn assert_split_after(list: Vec, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); let actual = cursor.split_after(); assert_cursor(before, current, &[], cursor.as_cursor()); mem::drop(cursor); assert_list(after, token, actual); }); } #[test] fn cursor_mut_split_after() { assert_split_after(create(0..4), 0, &[], "0", &["1", "2", "3"]); assert_split_after(create(0..4), 1, &["0"], "1", &["2", "3"]); assert_split_after(create(0..4), 2, &["0", "1"], "2", &["3"]); assert_split_after(create(0..4), 3, &["0", "1", "2"], "3", &[]); // Special-case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); let actual = cursor.split_after(); assert_twilight(&[], cursor.as_cursor()); mem::drop(cursor); assert_list(&[], token, actual); }); // Special-case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); let actual = cursor.split_after(); assert_twilight(&[], cursor.as_cursor()); mem::drop(cursor); assert_list(&["0", "1", "2", "3"], token, actual); }); } #[track_caller] fn assert_split_before(list: Vec, at: usize, before: &[&str], current: &str, after: &[&str]) { with_list(list, |token, list| { let mut cursor = place_cursor(token, list, at); let actual = cursor.split_before(); assert_cursor(&[], current, &after, cursor.as_cursor()); mem::drop(cursor); assert_list(before, token, actual); }); } #[test] fn cursor_mut_split_before() { assert_split_before(create(0..4), 0, &[], "0", &["1", "2", "3"]); assert_split_before(create(0..4), 1, &["0"], "1", &["2", "3"]); assert_split_before(create(0..4), 2, &["0", "1"], "2", &["3"]); assert_split_before(create(0..4), 3, &["0", "1", "2"], "3", &[]); // Special-case: "empty" with_list(create(0..0), |token, list| { let mut cursor = CursorMut::new_front(token, list); let actual = cursor.split_before(); assert_twilight(&[], cursor.as_cursor()); mem::drop(cursor); assert_list(&[], token, actual); }); // Special-case: "twilight" with_list(create(0..4), |token, list| { let mut cursor = place_cursor(token, list, 4); let actual = cursor.split_before(); assert_twilight(&[], cursor.as_cursor()); mem::drop(cursor); assert_list(&["0", "1", "2", "3"], token, actual); }); } } // mod tests ================================================ FILE: src/tripod_list/iter.rs ================================================ use ghost_cell::GhostToken; use super::{GhostNode, TripodList}; /// An iterator over a TripodList, self-sufficient once created as it carries its own token. pub struct Iter<'a, 'brand, T> { token: &'a GhostToken<'brand>, head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>, } impl<'a, 'brand, T> Iter<'a, 'brand, T> { /// Creates a new instance of the Iter. pub fn new(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self { let head_tail = list.head_tail.as_ref().map(|head_tail| { (&*head_tail.0, &*head_tail.1) }); Self { token, head_tail, } } // Internal: creates an empty instance. pub(super) fn empty(token: &'a GhostToken<'brand>) -> Self { Self { token, head_tail: None, } } // Internal: creates an instance over a slice of items. pub(super) fn slice( token: &'a GhostToken<'brand>, head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>, ) -> Self { Self { token, head_tail, } } } impl<'a, 'brand, T> Iterator for Iter<'a, 'brand, T> { type Item = &'a T; fn next(&mut self) -> Option { let (head, tail) = self.head_tail.take()?; let node = head.borrow(self.token); if head as *const _ != tail as *const _ { self.head_tail = node.next.as_ref().map(|n| { let n: &'a GhostNode<'_, _> = &*n; (n, tail) }); } else { self.head_tail = None; } Some(&node.value) } } impl<'a, 'brand, T> DoubleEndedIterator for Iter<'a, 'brand, T> { fn next_back(&mut self) -> Option { let (head, tail) = self.head_tail.take()?; let node = tail.borrow(self.token); if head as *const _ != tail as *const _ { self.head_tail = node.prev.as_ref().map(|n| { let n: &'a GhostNode<'_, _> = &*n; (head, n) }); } else { self.head_tail = None; } Some(&node.value) } } #[cfg(test)] mod tests { use super::super::tests::with_list; use super::*; #[test] fn empty() { with_list::(vec!(), |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(None, iterator.next()); assert_eq!(None, iterator.next_back()); }); } #[test] fn forward() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next().map(String::as_str)); assert_eq!(Some("3"), iterator.next().map(String::as_str)); assert_eq!(None, iterator.next()); }); } #[test] fn backward() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next_back().map(String::as_str)); assert_eq!(Some("0"), iterator.next_back().map(String::as_str)); assert_eq!(None, iterator.next_back()); }); } #[test] fn alternate() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(None, iterator.next()); assert_eq!(None, iterator.next_back()); }); } #[test] fn alternate_other() { let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect(); with_list(vec, |token, list| { let mut iterator = Iter::new(token, list); assert_eq!(Some("3"), iterator.next_back().map(String::as_str)); assert_eq!(Some("0"), iterator.next().map(String::as_str)); assert_eq!(Some("2"), iterator.next_back().map(String::as_str)); assert_eq!(Some("1"), iterator.next().map(String::as_str)); assert_eq!(None, iterator.next_back()); assert_eq!(None, iterator.next()); }); } } // mod tests ================================================ FILE: src/tripod_list.rs ================================================ //! A LinkedList, with externally supplied token. //! //! Unlike LinkedList, a TripodList has one additional pointer per node. In exchange, extra capabilities are unlocked. //! //! A number of operations normally implemented by traits cannot be successfully implemented on this collection due to //! the requirement of supplying the GhostToken externally. mod cursor; mod iter; pub use cursor::{Cursor, CursorMut}; pub use iter::Iter; use core::{ cell::Cell, mem, }; use ghost_cell::{GhostCell, GhostToken}; use static_rc::StaticRc; /// A safe implementation of a linked-list build upon `GhostCell` and `StaticRc`. /// /// The `TripodList` contains 3 pointers per node, rather than 2 for a standard doubly linked list, the extra pointer /// is used to temporarily anchor a node to the stack, guaranteeing its lifetime. pub struct TripodList<'brand, T> { length: usize, head_tail: Option<(ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>)>, } impl<'brand, T> TripodList<'brand, T> { /// Creates a fresh instance. pub fn new() -> Self { Self::default() } /// Appends all elements of `other`, in order, to the back of this list. /// /// After this call, `other` is empty /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) { let other_ht = if let Some(other_ht) = other.head_tail.take() { other_ht } else { return; }; self.head_tail = if let Some(self_ht) = self.head_tail.take() { let (new_head, mid_tail) = self_ht; let (mid_head, new_tail) = other_ht; let tripod = mid_head.borrow(token).deploy(); mid_tail.borrow_mut(token).next = Some(mid_head); tripod.borrow_mut(token).prev = Some(mid_tail); retract(tripod, token); Some((new_head, new_tail)) } else { Some(other_ht) }; self.length += other.length; other.length = 0; } /// Prepends all elements of `other`, in order, to the front of this list. /// /// After this call, `other` is empty /// /// # Complexity /// /// This operation is O(1) in the number of elements. /// /// No memory allocation or deallocation occurs. pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) { other.append(self, token); mem::swap(self, other); } /// Creates an iterator over self. pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> { Iter::new(token, self) } /// Creates a cursor pointing to the front element. pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_front(token, self) } /// Creates a mutable cursor pointing to the front element. pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_front(token, self) } /// Creates a cursor pointing to the back element. pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_back(token, self) } /// Creates a mutable cursor pointing to the back element. pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_back(token, self) } /// Returns whether the list is empty, or not. pub fn is_empty(&self) -> bool { self.length == 0 } /// Returns the number of elements in the list. pub fn len(&self) -> usize { self.length } /// Clears the list, destroying all elements. /// /// # Complexity /// /// This operation is O(N) in the number of elements. pub fn clear(&mut self, token: &mut GhostToken<'brand>) { while let Some(_) = self.pop_back(token) {} } /// Returns a reference to the front element of the list, if any. pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { self.front_node().map(|node| &node.borrow(token).value) } /// Returns a mutable reference to the front element of the list, if any. pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { self.front_node().map(move |node| &mut node.borrow_mut(token).value) } /// Returns a reference to the back element of the list, if any. pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { self.back_node().map(|node| &node.borrow(token).value) } /// Returns a mutable reference to the back element of the list, if any. pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { self.back_node().map(move |node| &mut node.borrow_mut(token).value) } /// Pushes an element to the front of the list. pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) { let (one, two) = Self::new_thirds(value, token); let head_tail = if let Some((head, tail)) = self.head_tail.take() { head.borrow_mut(token).prev = Some(one); two.borrow_mut(token).next = Some(head); (two, tail) } else { (one, two) }; self.length += 1; self.head_tail = Some(head_tail); } /// Removes and returns the front element of the list, if any. pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option { let (head, tail) = self.head_tail.take()?; let tripod = head.borrow(token).deploy(); let (one, two) = if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) { (head, tail) } else { let next = head.borrow_mut(token).next.take() .expect("Non-tail should have a next node"); let other_head = next.borrow_mut(token).prev.take() .expect("Non-head should have a previous node"); self.head_tail = Some((next, tail)); (head, other_head) }; self.length -= 1; Some(Self::into_inner((one, two, tripod))) } /// Pushes an element to the back of the list. pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) { let (one, two) = Self::new_thirds(value, token); let head_tail = if let Some((head, tail)) = self.head_tail.take() { tail.borrow_mut(token).next = Some(one); two.borrow_mut(token).prev = Some(tail); (head, two) } else { (one, two) }; self.length += 1; self.head_tail = Some(head_tail); } /// Removes and returns the back element of the list, if any. pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option { let (head, tail) = self.head_tail.take()?; let tripod = tail.borrow(token).deploy(); let (one, two) = if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) { (head, tail) } else { let prev = tail.borrow_mut(token).prev.take() .expect("Non-head should have a previous node"); let other_tail = prev.borrow_mut(token).next.take() .expect("Non-tail should have a next node"); self.head_tail = Some((head, prev)); (other_tail, tail) }; self.length -= 1; Some(Self::into_inner((one, two, tripod))) } /// Splits the list in two at the given index. Returns a list containing everything after the given index, inclusive. /// /// Returns None if the given index is out of bounds. /// /// # Complexity /// /// This operations is O(min(`at`, N)), where N is the number of elements. /// /// No memory allocation or deallocation occurs. pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Self { assert!(at < self.length, "at ({}) >= self.len() ({})", at, self.length); // This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity. let mut cursor = self.cursor_front_mut(token); if at == 0 { cursor.move_prev(); } else { for _ in 0..(at-1) { cursor.move_next(); } } cursor.split_after() } /// Removes the element at the given index, and returns it, if the index is within bounds. /// /// # Complexity /// /// This operations is O(min(`at`, N)), where N is the number of elements. /// /// No memory allocation occurs, and a single memory deallocation occurs. pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> T { assert!(at < self.length, "at ({}) >= self.len() ({})", at, self.length); // This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity. let mut cursor = self.cursor_front_mut(token); for _ in 0..at { cursor.move_next(); } cursor.remove_current().expect("Element, since at < self.length") } // Internal: returns a reference to the front node, if any. fn front_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.as_ref().map(|ht| &*ht.0) } // Internal: returns a reference to the front node, if any. fn back_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.as_ref().map(|ht| &*ht.1) } // Internal: creates a node with the value, and returns 2/3 of its pointers, the remaining tucked into its tripod field. fn new_thirds(value: T, token: &GhostToken<'brand>) -> (ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>) { let node = Node { value, prev: None, next: None, tripod: Cell::new(None), }; let full = FullNodePtr::new(GhostNode::new(node)); let (partial, tripod) = StaticRc::split::<2, 1>(full); partial.borrow(token).retract(tripod); StaticRc::split::<1, 1>(partial) } // Internal: takes 3 1/3 pointers, reassemble them, and return their inner value. fn into_inner(thirds: ThirdTuple<'brand, T>) -> T { let partial = TwoThirdsNodePtr::join(thirds.0, thirds.1); let full = FullNodePtr::join(partial, thirds.2); let ghost_cell = FullNodePtr::into_inner(full); let node = GhostNode::into_inner(ghost_cell); // If the node still has a prev and next, they are leaked. debug_assert!(node.prev.is_none()); debug_assert!(node.next.is_none()); debug_assert!(node.tripod.replace(None).is_none()); node.value } } impl<'brand, T> Default for TripodList<'brand, T> { fn default() -> Self { Self { length: 0, head_tail: None, } } } // // Implementation // struct Node<'brand, T> { value: T, prev: Option>, next: Option>, tripod: Cell>>, } impl<'brand, T> Node<'brand, T> { // Internal; deploys the tripod. fn deploy(&self) -> ThirdNodePtr<'brand, T> { self.tripod.take().expect("Tripod not to be None") } // Internal; retracts the tripod. fn retract(&self, tripod: ThirdNodePtr<'brand, T>) { let previous = self.tripod.replace(Some(tripod)); debug_assert!(previous.is_none()); } } fn retract<'brand, T>(tripod: ThirdNodePtr<'brand, T>, token: &mut GhostToken<'brand>) { let previous = static_rc::lift_with_mut(Some(tripod), token, |tripod, token| { tripod.as_ref().expect("Some").borrow_mut(token).tripod.get_mut() }); debug_assert!(previous.is_none(), "Node should not have any tripod to retract it!"); } type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>; type ThirdNodePtr<'brand, T> = StaticRc, 1, 3>; type TwoThirdsNodePtr<'brand, T> = StaticRc, 2, 3>; type FullNodePtr<'brand, T> = StaticRc, 3, 3>; type ThirdTuple<'brand, T> = (ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>); #[cfg(test)] mod tests { use std::{ panic::{self, AssertUnwindSafe}, ops::Range, }; use super::*; #[track_caller] fn assert_list_mut<'brand>(expected: &[&str], token: &mut GhostToken<'brand>, list: &mut TripodList<'brand, String>) { let actual = collect(list.iter(token)); assert_eq!(expected, actual); assert_eq!(expected.len(), list.len()); assert_eq!(expected.is_empty(), list.is_empty()); list.clear(token); } #[track_caller] pub(crate) fn assert_list<'brand>(expected: &[&str], token: &mut GhostToken<'brand>, mut list: TripodList<'brand, String>) { assert_list_mut(expected, token, &mut list); } #[track_caller] fn assert_list_append(list: Vec, append: Vec, expected: &[&str]) { with_list_duo(list, append, |token, list, other| { list.append(other, token); assert_list_mut(expected, token, list); assert_list_mut(&[], token, other); }); } #[test] fn list_append() { // Append empty list assert_list_append(create(0..0), create(0..0), &[]); assert_list_append(create(0..1), create(0..0), &["0"]); assert_list_append(create(0..4), create(0..0), &["0", "1", "2", "3"]); // Append single element list assert_list_append(create(0..0), create(4..5), &["4"]); assert_list_append(create(0..1), create(4..5), &["0", "4"]); assert_list_append(create(0..4), create(4..5), &["0", "1", "2", "3", "4"]); // Append multi element list assert_list_append(create(0..0), create(4..7), &["4", "5", "6"]); assert_list_append(create(0..1), create(4..7), &["0", "4", "5", "6"]); assert_list_append(create(0..4), create(4..7), &["0", "1", "2", "3", "4", "5", "6"]); } #[track_caller] fn assert_list_split_off(list: Vec, at: usize, expected_list: &[&str], expected_result: &[&str]) { with_list(list, |token, list| { let result = list.split_off(at, token); assert_list_mut(expected_list, token, list); assert_list(expected_result, token, result); }); } #[test] fn list_split_off() { assert_list_split_off(create(0..4), 0, &[], &["0", "1", "2", "3"]); assert_list_split_off(create(0..4), 1, &["0"], &["1", "2", "3"]); assert_list_split_off(create(0..4), 2, &["0", "1"], &["2", "3"]); assert_list_split_off(create(0..4), 3, &["0", "1", "2"], &["3"]); } #[test] #[should_panic] fn list_split_off_out_of_bounds() { with_list(create(0..4), |token, list| { list.split_off(4, token); }); } #[track_caller] fn assert_list_remove(list: Vec, at: usize, expected_list: &[&str], expected_result: &str) { with_list(list, |token, list| { let result = list.remove(at, token); assert_eq!(expected_result, result); assert_list_mut(expected_list, token, list); }); } #[test] fn list_remove() { assert_list_remove(create(0..4), 0, &["1", "2", "3"], "0"); assert_list_remove(create(0..4), 1, &["0", "2", "3"], "1"); assert_list_remove(create(0..4), 2, &["0", "1", "3"], "2"); assert_list_remove(create(0..4), 3, &["0", "1", "2"], "3"); } #[test] #[should_panic] fn list_remove_out_of_bounds() { with_list(create(0..4), |token, list| { list.remove(4, token); }); } pub(crate) fn create(range: Range) -> Vec { range.map(|n| n.to_string()).collect() } pub(crate) fn collect<'a>(iter: Iter<'a, '_, String>) -> Vec<&'a str> { iter.map(String::as_str).collect() } pub(crate) fn with_list(initial: Vec, fun: F) -> R where F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodList<'brand, T>) -> R, { GhostToken::new(|mut token| { let mut list = TripodList::new(); for value in initial { list.push_back(value, &mut token); } let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut list))); list.clear(&mut token); result.expect("No Panic") }) } pub(crate) fn with_list_duo(first: Vec, second: Vec, fun: F) -> R where F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodList<'brand, T>, &mut TripodList<'brand, T>) -> R, { GhostToken::new(|mut token| { let mut first_list = TripodList::new(); let mut second_list = TripodList::new(); for value in first { first_list.push_back(value, &mut token); } for value in second { second_list.push_back(value, &mut token); } let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut first_list, &mut second_list))); first_list.clear(&mut token); second_list.clear(&mut token); result.expect("No Panic") }) } } // mod tests ================================================ FILE: src/tripod_tree/cursor.rs ================================================ use core::{ cmp, mem, ops::Range, }; use ghost_cell::GhostToken; use super::{GhostNode, QuarterNodePtr, Side, TripodTree}; /// A Cursor over the TripodTree. /// /// The Cursor contains a "twilight" non-element between the leaves and the root, that is: /// /// - Going "up" from the root points the cursor to the "twilight" non-element. /// - Going "left", respectively "right", from any node without a "left" (resp. "right") sub-tree points the cursor /// to the "twilight" non-element. /// /// A cursor pointing to the "twilight" non-element cannot go "up", and going either "left" or "right" points the /// cursor back to the root. pub struct Cursor<'a, 'brand, T> { token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>, node: Option<&'a GhostNode<'brand, T>>, index: usize, } // Constant time cursor navigation. impl<'a, 'brand, T> Cursor<'a, 'brand, T> { /// Creates a new cursor pointing at the root of the tree, if any. pub fn new(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self { let (node, index) = Self::root_of(token, tree); Self { token, index, node, tree, } } /// Returns the index of the cursor, if any. /// /// If the cursor points to the "twilight" non-element, None is returned. pub fn index(&self) -> Option { self.node.map(|_| self.index) } /// Returns the range of indices covered by the sub-tree rooted at node the cursor is pointing at. /// /// If the cursor points to the new "twilight" non-element, None is returned. pub fn range(&self) -> Range { self.node.map(|node| { let left_size = node.borrow(self.token).left_size(self.token); let right_size = node.borrow(self.token).right_size(self.token); (self.index - left_size)..(self.index + right_size + 1) }).unwrap_or(0..0) } /// Moves the cursor to the root, if any. pub fn move_to_root(&mut self) { *self = Self::new(self.token, self.tree) } /// Moves the cursor to the parent node, if any. /// /// If the cursor points to the "twilight" non-element, nothing happens. pub fn move_up(&mut self) { let (node, index) = self.peek_up_node(); self.index = index; self.node = node; } /// Moves the cursor to the left child. /// /// If the element the cursor points to has no left child, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_left(&mut self) { let (node, index) = self.peek_left_node(); self.index = index; self.node = node; } /// Moves the cursor to the right child. /// /// If the element the cursor points to has no right child, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_right(&mut self) { let (node, index) = self.peek_right_node(); self.index = index; self.node = node; } /// Moves the cursor to the child element on the given side. /// /// If the element the cursor points to has no such element, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_down(&mut self, side: Side) { let (node, index) = self.peek_down_node(side); self.index = index; self.node = node; } /// Attempts to move the cursor to the parent node, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no parent node, or is the "twilight" element, does not move. pub fn try_move_up(&mut self) -> Option<&'a T> { let (node, index) = self.peek_up_node(); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Attempts to move the cursor to the left child, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no left child, or is the "twilight" element, does not move. pub fn try_move_left(&mut self) -> Option<&'a T> { let (node, index) = self.peek_left_node(); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Attempts to move the cursor to the right child, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no right child, or is the "twilight" element, does not move. pub fn try_move_right(&mut self) -> Option<&'a T> { let (node, index) = self.peek_right_node(); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Attempts to move the cursor down to the given side, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor is pointing to has no child on that side, or is the "twilight" non-element, nothing /// happens and None is returned. pub fn try_move_down(&mut self, side: Side) -> Option<&'a T> { let (node, index) = self.peek_down_node(side); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Returns a reference to the current element, if any. pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the up element, if any. pub fn peek_up(&self) -> Option<&'a T> { self.peek_up_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the left child, if any. pub fn peek_left(&self) -> Option<&'a T> { self.peek_left_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the right child, if any. pub fn peek_right(&self) -> Option<&'a T> { self.peek_right_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the child element on the given side, if any. pub fn peek_down(&self, side: Side) -> Option<&'a T> { self.peek_down_node(side).0.map(|node| &node.borrow(self.token).value) } // Internal; extract the root and its index from the tree. fn root_of(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> (Option<&'a GhostNode<'brand, T>>, usize) { let root = tree.root.as_ref().map(|node| &**node); let index = root.map(|node| node.borrow(token).index(token)).unwrap_or(0); (root, index) } // Internal; returns a reference to the up GhostNode, and the matching index. fn peek_up_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) { if let Some(node) = self.node { let node = node.borrow(self.token); let parent = node.up(); let index = if let Some(parent) = parent { let parent = parent.borrow(self.token); if node.is_aliased(parent.left()) { self.index + 1 + node.right_size(self.token) } else { debug_assert!(node.is_aliased(parent.right())); self.index - 1 - node.left_size(self.token) } } else { self.len() }; (parent, index) } else { (self.node, self.len()) } } // Internal; returns a reference to the left GhostNode, and the matching index. fn peek_left_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) { if let Some(node) = self.node { let node = node.borrow(self.token); let dest = node.left(); let index = if let Some(left) = dest { self.index - 1 - left.borrow(self.token).right_size(self.token) } else { self.len() }; (dest, index) } else { Self::root_of(self.token, self.tree) } } // Internal; returns a reference to the right GhostNode, and the matching index. fn peek_right_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) { if let Some(node) = self.node { let node = node.borrow(self.token); let dest = node.right(); let index = if let Some(right) = dest { self.index + 1 + right.borrow(self.token).left_size(self.token) } else { self.len() }; (dest, index) } else { Self::root_of(self.token, self.tree) } } // Internal; returns a reference to the child GhostNode on the given side, and the matching index. fn peek_down_node(&self, side: Side) -> (Option<&'a GhostNode<'brand, T>>, usize) { if let Some(node) = self.node { let node = node.borrow(self.token); let dest = node.child(side); let index = if let Some(dest) = dest { let opposite_size = dest.borrow(self.token).child_size(side.opposite(), self.token); match side { Side::Left => self.index - 1 - opposite_size, Side::Right => self.index + 1 + opposite_size, } } else { self.len() }; (dest, index) } else { Self::root_of(self.token, self.tree) } } } // Logarithmic cursor navigation. impl<'a, 'brand, T> Cursor<'a, 'brand, T> { /// Creates a new cursor pointing at the front element of the tree, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn new_front(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self { let mut cursor = Self::new(token, tree); while let Some(_) = cursor.try_move_left() {} debug_assert_eq!(0, cursor.index); cursor } /// Creates a new cursor pointing at the back element of the tree, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn new_back(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self { let mut cursor = Self::new(token, tree); while let Some(_) = cursor.try_move_right() {} debug_assert_eq!(cursor.len() - 1, cursor.index); cursor } /// Moves the cursor to the front element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_to_front(&mut self) { *self = Self::new_front(self.token, self.tree); } /// Moves the cursor to the back element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_to_back(&mut self) { *self = Self::new_back(self.token, self.tree); } /// Moves the cursor to the next element, if any. /// /// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the root /// and the leaves. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_next(&mut self) { let (node, index) = self.peek_next_node(); self.index = index; self.node = node; } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the root /// and the leaves. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_prev(&mut self) { let (node, index) = self.peek_prev_node(); self.index = index; self.node = node; } /// Moves the cursor to the element at the given index. /// /// If there is no such element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). /// /// # Panics /// /// If `at` is strictly greater than `tree.len()`. pub fn move_to(&mut self, at: usize) { self.node = self.peek_at_node(at); self.index = at; } /// Attempts to move the cursor to the next element, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no next element, or is the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn try_move_next(&mut self) -> Option<&'a T> { let (node, index) = self.peek_next_node(); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Attempts to move the cursor to the previous element, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no previous element, or is the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn try_move_prev(&mut self) -> Option<&'a T> { let (node, index) = self.peek_prev_node(); if let Some(_) = node { self.index = index; self.node = node; self.current() } else { None } } /// Attempts to move the cursor to the element at the given index, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If there is not such element, or the cursor points to the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). /// /// # Panics /// /// If `at` is strictly greater than `tree.len()`. pub fn try_move_to(&mut self, at: usize) -> Option<&'a T> { self.node?; let node = self.peek_at_node(at); if let Some(_) = node { self.index = at; self.node = node; self.current() } else { None } } /// Returns a reference to the next element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the previous element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the element at the given index, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_at(&self, at: usize) -> Option<&'a T> { self.peek_at_node(at).map(|node| &node.borrow(self.token).value) } // Internal; returns the length of the tree. fn len(&self) -> usize { self.tree.len(self.token) } // Internal; returns a reference to the GhostNode at the next index. fn peek_next_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) { let index = if let Some(_) = self.node { self.index + 1 } else { 0 }; (self.peek_at_node(index), index) } // Internal; returns a reference to the GhostNode at the previous index. fn peek_prev_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) { let index = if let Some(_) = self.node { self.index.checked_sub(1).unwrap_or_else(|| self.len()) } else { self.len().checked_sub(1).unwrap_or(0) }; (self.peek_at_node(index), index) } // Internal; returns a reference to the GhostNode at the specific index. // // Panics if the index is "too" out of bounds; returns the "twilight" non-element if the index is only 1 out of bounds. fn peek_at_node(&self, at: usize) -> Option<&'a GhostNode<'brand, T>> { let length = self.len(); assert!(at <= length, "at ({}) > self.tree.len() ({})", at, length); if at == length { return None; } if at == self.index { return self.node; } let mut cursor = match (self.node, self.tree.root.as_ref().map(|n| &**n)) { (Some(_), Some(root)) => { let root_index = root.borrow(self.token).index(self.token); if at >= root_index && root_index > self.index { Cursor::new(self.token, self.tree) } else if at <= root_index && root_index < self.index { Cursor::new(self.token, self.tree) } else { self.clone() } }, (Some(_), None) => self.clone(), (None, Some(_)) => Cursor::new(self.token, self.tree), (None, None) => unreachable!("at >= length, then"), }; // In this case, move start to the first common ancestor of start and the node at index `at`. if self.index == cursor.index { while !cursor.range().contains(&at) { cursor.move_up(); } } // From then on, we are guaranteed that `cursor` is pointing to an ancestor of `at`, so it's somewhere down. let mut max_iteration = length + 1; loop { use cmp::Ordering::*; let index = cursor.index; debug_assert!(cursor.range().contains(&at), "{:?} does not contain {}", cursor.range(), at); match at.cmp(&index) { Less => { cursor.move_left(); debug_assert!(cursor.index < index); }, Equal => break, Greater => { cursor.move_right(); debug_assert!(cursor.index > index); }, } debug_assert!(max_iteration > 0); max_iteration = max_iteration.saturating_sub(1); } debug_assert_eq!(at, cursor.index); cursor.node } } impl<'a, 'brand, T> Clone for Cursor<'a, 'brand, T> { fn clone(&self) -> Self { *self } } impl<'a, 'brand, T> Copy for Cursor<'a, 'brand, T> {} /// A mutable cursor over the TripodTree. /// /// A mutable cursor allows freely moving back-and-forth amongst the elements of the tree, and mutate the tree as any /// point. /// /// Cursors index the tree in a logically circular way. To accomodate this, there is a "twilight" non-element /// represented by `None` between the root and leaves of the tree. /// /// # Warning. /// /// This cursor mutates the tree as it iterates. Although the tree is left in a safe state by construction, forgoing the /// drop of this cursor -- unless it points to the "twilight" non-element -- will leave the tree in an unusable state. /// /// Any further mutable operation on the tree, including calling `clear`, is at risk of panicking. pub struct CursorMut<'a, 'brand, T> { token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>, node: Option>, index: usize, } // Constant time cursor navigation. impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Creates a new instance pointing to the front element of the tree, if any. pub fn new(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self { let (node, index) = Self::root_of(token, tree); let node = node.map(|node| node.borrow(token).deploy()); Self { token, index, node, tree, } } /// Returns a read-only cursor pointing to the current element. pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> { let token = &*self.token; let index = self.index; let node = self.node.as_ref().map(|rc| &**rc); let tree = &*self.tree; Cursor { token, index, node, tree, } } /// Returns the index of the element pointed to by the cursor in the tree. /// /// If the cursor currently points to the "twilight" non-element, returns None. pub fn index(&self) -> Option { self.node.as_ref().map(|_| self.index) } /// Returns the range of indices covered by the sub-tree rooted at node the cursor is pointing at. /// /// If the cursor points to the new "twilight" non-element, None is returned. pub fn range(&self) -> Range { self.as_cursor().range() } /// Moves the cursor to the parent element, if any. /// /// If the cursor points to the "twilight" non-element, nothing happens. pub fn move_up(&mut self) { let (node, index) = self.peek_up_node(); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves the cursor to the left element. /// /// If the element the cursor points to has no left element, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_left(&mut self) { let (node, index) = self.peek_left_node(); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves the cursor to the right element. /// /// If the element the cursor points to has no right element, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_right(&mut self) { let (node, index) = self.peek_right_node(); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves the cursor to the child element on the design side. /// /// If the element the cursor points to has no such element, moves to the "twilight" non-element. /// /// If the cursor points to the "twilight" non-element, moves to the root instead, if any. pub fn move_down(&mut self, side: Side) { let (node, index) = self.peek_down_node(side); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves to the cursor to the root of the tree. /// /// If there is no such element, moves to the "twilight" non-element. pub fn move_to_root(&mut self) { // If list empty, no root to move to. if self.tree.is_empty() { return; } // If pointing at root, no need to move. if self.node.is_some() && self.peek_up().is_none() { return; } let root_tripod = self.tree.root.as_ref().map(|node| self.deploy_tripod(node)); let root_index = root_tripod.as_ref().map(|tripod| tripod.borrow(self.token).index(self.token)).unwrap_or(0); self.switch_tripod(root_tripod, root_index); } /// Attempts to move the cursor to the parent element, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no parent element, or is the "twilight" element, nothing /// happens and None is returned. pub fn try_move_up(&mut self) -> Option<&mut T> { let (node, index) = self.peek_up_node(); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Attempts to move the cursor to the left child, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no left child, or is the "twilight" non-element, nothing /// happens and None is returned. pub fn try_move_left(&mut self) -> Option<&mut T> { let (node, index) = self.peek_left_node(); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Attempts to move the cursor to the right child, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no right child, or is the "twilight" non-element, nothing /// happens and None is returned. pub fn try_move_right(&mut self) -> Option<&mut T> { let (node, index) = self.peek_right_node(); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Attempts to move the cursor down to the given side, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor is pointing to has no child on that side, or is the "twilight" non-element, nothing /// happens and None is returned. pub fn try_move_down(&mut self, side: Side) -> Option<&mut T> { let (node, index) = self.peek_down_node(side); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Returns a reference to the current element, if any. pub fn current(&mut self) -> Option<&mut T> { let tripod = self.node.as_ref()?; Some(&mut tripod.borrow_mut(self.token).value) } /// Returns a reference to the up element, if any. pub fn peek_up(&self) -> Option<&T> { self.peek_up_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the left element, if any. pub fn peek_left(&self) -> Option<&T> { self.peek_left_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the right element, if any. pub fn peek_right(&self) -> Option<&T> { self.peek_right_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the child element on the given side, if any. pub fn peek_down(&self, side: Side) -> Option<&T> { self.peek_down_node(side).0.map(|node| &node.borrow(self.token).value) } // Internal; extract the root and its index from the tree. fn root_of<'b>(token: &'b GhostToken<'brand>, tree: &'b TripodTree<'brand, T>) -> (Option<&'b GhostNode<'brand, T>>, usize) { let root = tree.root.as_ref().map(|node| &**node); let index = root.map(|node| node.borrow(token).index(token)).unwrap_or(0); (root, index) } // Internal; deploys a tripod. fn deploy_tripod(&self, node: &GhostNode<'brand, T>) -> QuarterNodePtr<'brand, T> { node.borrow(self.token).deploy() } // Internal; deploys a tripod. fn retract_tripod(&mut self, node: QuarterNodePtr<'brand, T>) { super::retract(node, self.token); } // Internal; replace the current tripod with another, retracting the former if any. fn switch_tripod(&mut self, new_tripod: Option>, index: usize) { self.index = index; if let Some(tripod) = mem::replace(&mut self.node, new_tripod) { super::retract(tripod, self.token); } } // Internal; returns a reference to the up GhostNode, and the matching index. fn peek_up_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_up_node() } // Internal; returns a reference to the left GhostNode, and the matching index. fn peek_left_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_left_node() } // Internal; returns a reference to the right GhostNode, and the matching index. fn peek_right_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_right_node() } // Internal; returns a reference to the child GhostNode on the given side, and the matching index. fn peek_down_node(&self, side: Side) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_down_node(side) } } // Logarithmic cursor navigation. impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Creates a new cursor pointing at the front element of the tree, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn new_front(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self { let mut cursor = Self::new(token, tree); while let Some(_) = cursor.try_move_left() {} debug_assert_eq!(0, cursor.index); cursor } /// Creates a new cursor pointing at the back element of the tree, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn new_back(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self { let mut cursor = Self::new(token, tree); while let Some(_) = cursor.try_move_right() {} debug_assert_eq!(cursor.len() - 1, cursor.index); cursor } /// Moves the cursor to the next element, if any. /// /// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the root /// and the leaves. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_next(&mut self) { let (node, index) = self.peek_next_node(); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves the cursor to the previous element, if any. /// /// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the root /// and the leaves. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_prev(&mut self) { let (node, index) = self.peek_prev_node(); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); } /// Moves the cursor to the element at the given index. /// /// If there is no such element, then the cursor moves to the "twilight" non-element, which exists between the front /// and back element. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). /// /// # Panics /// /// If `at` is strictly greater than `tree.len()`. pub fn move_to(&mut self, at: usize) { if self.index == at { return; } let node = self.peek_at_node(at); let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, at); } /// Moves the cursor to the front element. /// /// If there is no such element, then the cursor moves to the "twilight" non-element. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_to_front(&mut self) { self.move_to_root(); while let Some(_) = self.try_move_left() {} } /// Moves the cursor to the front element. /// /// If there is no such element, then the cursor moves to the "twilight" non-element. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn move_to_back(&mut self) { self.move_to_root(); while let Some(_) = self.try_move_right() {} } /// Attempts to move the cursor to the next element, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no next element, or is the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn try_move_next(&mut self) -> Option<&mut T> { let (node, index) = self.peek_next_node(); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Attempts to move the cursor to the previous element, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If the element the cursor points to has no previous element, or is the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn try_move_prev(&mut self) -> Option<&mut T> { let (node, index) = self.peek_prev_node(); if let Some(_) = node { let new_tripod = node.map(|node| self.deploy_tripod(node)); self.switch_tripod(new_tripod, index); self.current() } else { None } } /// Attempts to move the cursor to the element at the given index, if any. /// /// Returns a reference to the pointed to element, in case of success. /// /// If there is not such element, or the cursor points to the "twilight" element, does not move. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). /// /// # Panics /// /// If `at` is strictly greater than `tree.len()`. pub fn try_move_to(&mut self, at: usize) -> Option<&mut T> { self.node.as_ref()?; if self.index == at { return self.current(); } let node = self.peek_at_node(at); if let Some(node) = node { let new_tripod = Some(self.deploy_tripod(node)); self.switch_tripod(new_tripod, at); self.current() } else { None } } /// Returns a reference to the next element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the previous element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().0.map(|node| &node.borrow(self.token).value) } /// Returns a reference to the element at the given index, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of element. /// - Space: O(1). pub fn peek_at(&self, at: usize) -> Option<&T> { self.peek_at_node(at).map(|node| &node.borrow(self.token).value) } // Internal; returns the length of the tree. fn len(&self) -> usize { self.tree.len(self.token) } // Internal; returns a reference to the GhostNode at the next index. fn peek_next_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_next_node() } // Internal; returns a reference to the GhostNode at the previous index. fn peek_prev_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) { self.as_cursor().peek_prev_node() } // Internal; returns a reference to the GhostNode at the specific index. // // Panics if the index is "too" out of bounds; returns the "twilight" non-element if the index is only 1 out of bounds. fn peek_at_node(&self, at: usize) -> Option<&GhostNode<'brand, T>> { self.as_cursor().peek_at_node(at) } } // Edit cursor operations. impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { /// Inserts a new element in the tree after the current one. /// /// See `splice_after` for the details. /// /// A single memory allocation is performed. pub fn insert_after(&mut self, value: T) { let mut other = TripodTree::singleton(value, self.token); self.splice_after(&mut other); } /// Inserts a new element in the tree before the current one. /// /// See `splice_before` for the details. /// /// A single memory allocation is performed. pub fn insert_before(&mut self, value: T) { let mut other = TripodTree::singleton(value, self.token); self.splice_before(&mut other); } /// Removes the current element from the tree. /// /// See `remove_current_as_tree` for details. /// /// A single memory deallocation is performed. pub fn remove_current(&mut self) -> Option { let removed = self.remove_current_as_tree(); debug_assert!(removed.len(self.token) <= 1, "{} > 1", removed.len(self.token)); removed.root.map(|root| { TripodTree::node_into_inner(root, self.token) }) } /// Removes the current element from the tree and returns it as a `TripodTree`. /// /// The removed element is returned, and the cursor is moved to point to the next element, if any. /// /// If the cursor is pointing at the "twilight" non-element, then no element is removed and `None` is returned. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occur. pub fn remove_current_as_tree(&mut self) -> TripodTree<'brand, T> { // Short circuit if not interesting. if self.node.is_none() { return TripodTree::new(); } self.describe_self("remove_current_as_tree (begin)"); // Memorize index, to restore it. let index = self.index; // Push node down until it's a leaf in the deepest sub-tree, recursively => O(log N). self.sift_down(); // Remove leaf, fixing up parents if any. let current_tripod = self.node.take().expect("There should be a node"); let _current_size = current_tripod.borrow(self.token).size; debug_assert_eq!(1, _current_size, "And this node should be a leaf"); let current = if let Some(parent) = current_tripod.borrow_mut(self.token).up.take() { let parent_tripod = self.deploy_tripod(&parent); let parent_side = current_tripod.borrow(self.token).is_child_of(parent.borrow(self.token)).expect("Child!"); let current = parent_tripod.borrow_mut(self.token).replace_child(parent_side, parent).expect("Current!"); self.adjust_size(&parent_tripod); // Removing the left leaf means the parent takes its place, index-wise. // Removing the right leaf and switching to the parent, however, requires adjusting the index. if parent_side == Side::Right { self.index -= 1; } // O(log N). self.rebalance_tree_single(parent_tripod); self.move_to(index); current } else { // The node is the current root, and it's a leaf => no-one else here! self.tree.root.take().expect("Non-empty!") }; self.retract_tripod(current_tripod); self.describe_self("remove_current_as_tree (end)"); TripodTree::from_quarter(current, self.token) } /// Inserts a new tree in the tree after the current one. /// /// Although the cursor remains pointed to the same element, the position of the element may have changed /// drastically due to rebalancing. /// /// If the cursor is pointing at the "twilight" non-element, then the new tree is inserted at the front. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occur. pub fn splice_after(&mut self, other: &mut TripodTree<'brand, T>) { // We'll be getting back to this index. let original = self.index(); self.splice_impl(Side::Right, other); self.move_to(original.unwrap_or_else(|| self.len())); debug_assert_eq!(original, self.index()); } /// Inserts a new tree in the tree before the current one. /// /// Although the cursor remains pointed to the same element, the position of the element may have changed /// drastically due to rebalancing. /// /// If the cursor is pointing at the "twilight" non-element, then the new tree is inserted at the back. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occur. pub fn splice_before(&mut self, other: &mut TripodTree<'brand, T>) { // We'll be getting back to this index. let original = self.index(); let other_size = other.len(self.token); self.splice_impl(Side::Left, other); self.move_to(original.map(|n| n + other_size).unwrap_or_else(|| self.len())); debug_assert_eq!(original.map(|n| n + other_size), self.index()); } /// Splits the tree into two after the current element. /// /// Returns a tree consisting of everything after the current element. /// /// If the cursor is pointing at the "twilight" non-element, returns everything. /// /// # Complexity /// /// - Time: O(log² N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occur. pub fn split_after(&mut self) -> TripodTree<'brand, T> { let result = self.split_impl(Side::Right); self.move_to_back(); result } /// Splits the tree into two before the current element. /// /// Returns a tree consisting of everything before the current element. /// /// If the cursor is pointing at the "twilight" non-element, returns everything. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occur. pub fn split_before(&mut self) -> TripodTree<'brand, T> { let result = self.split_impl(Side::Left); self.move_to_front(); result } // Internal; sift down current index, until it's a leaf, by pushing it alongst the deepest path. // // Complexity: Time O(log N), Space O(1). fn sift_down(&mut self) { // O(log N) iterations, each doing O(1) work. loop { let current_tripod = self.node.take().expect("Non-twilight"); let _current_size = current_tripod.borrow(self.token).size; let left_size = current_tripod.borrow(self.token).left_size(self.token); let right_size = current_tripod.borrow(self.token).right_size(self.token); debug_assert_eq!(_current_size, 1 + left_size + right_size, "sift_down - {} != 1 + {} + {}", _current_size, left_size, right_size); // Leaf! if left_size == 0 && right_size == 0 { self.node = Some(current_tripod); return; } // Going down let side = if left_size > right_size { Side::Left } else { Side::Right }; self.swap_child_from(side, current_tripod); } } // Internal; splice_before/after, without any guarantee with regard to the position of the index. // // Complexity: Time O(log² N), Space O(1). fn splice_impl(&mut self, side: Side, other: &mut TripodTree<'brand, T>) { self.describe_self("splice_impl (begin)"); let other_root = if let Some(other_root) = other.root.take() { other_root } else { self.describe_self("splice_impl (end) (empty)"); return; }; if self.tree.is_empty() { self.index = other_root.borrow(self.token).size; self.tree.root = Some(other_root); return; } let opposite = side.opposite(); // No root. if self.index().is_none() { match side { // Place at the back. Side::Left => self.move_to_back(), // Place at the front. Side::Right => self.move_to_front(), } self.set_subtree(opposite, other_root); self.describe_self("splice_impl (end) (twilight)"); return; } // Otherwise, place at opposite-side-most child of side sub-tree. if let Some(_) = self.try_move_down(side) { while let Some(_) = self.try_move_down(opposite) {} self.set_subtree(opposite, other_root); } else { // Unless there's no side child. self.set_subtree(side, other_root); } self.describe_self("splice_impl (end)"); } // Internal; splits the tree into two, taking all elements on the given side into the new tree. // // Complexity: Time O(log² N), Space O(1). fn split_impl(&mut self, side: Side) -> TripodTree<'brand, T> { if self.node.is_none() { self.index = 0; return mem::replace(self.tree, TripodTree::new()); } // Special cases, taking a left-most or right-most sub-tree. { let node = self.node.as_ref().expect("Non-empty"); match side { Side::Left if self.range().start == 0 => { let result = TripodTree { root: Self::take_child(side, node, self.token) }; self.index = 0; let current_tripod = self.node.take().expect("Non-empty"); self.rebalance_tree_single(current_tripod); return result; }, Side::Right if self.range().end == self.len() => { let result = TripodTree { root: Self::take_child(side, node, self.token) }; let current_tripod = self.node.take().expect("Non-empty"); self.rebalance_tree_single(current_tripod); return result; }, _ => (), } } // Computing which elements should go, and which shouldn't, is fairly complicated. // // The one exception: when the current node is the root, then one side stays and one side goes! // // So... we're going to have a simple plan: // // 1. Make the current node root. // a. Keep its children balanced. // 2. Strip off its `side` child, this is our tree. // 3. Repeatedly rebalance until the entire tree is balanced. // 4. Profit! self.describe_self("split_impl (begin)"); // 1. Make the current node root => O(log N), from O(log N) iterations each doing O(1) work. while let Some(parent_side) = self.node.as_ref().and_then(|node| node.borrow(self.token).is_child(self.token)) { self.move_up(); let parent_tripod = self.node.take().expect("Non-empty"); self.rotate_child_from(parent_side, parent_tripod); // a. Keep its children balanced. let parent = self.node.take().expect("Non-empty"); self.rebalance_child(Side::Left, &parent); self.rebalance_child(Side::Right, &parent); self.node = Some(parent); self.describe_self("split_impl (post incremental rotation)"); } self.describe_self("split_impl (pre split)"); // 2. Strip off its `side` child => O(1). let result = { let node = self.node.as_ref().expect("Non-empty"); TripodTree { root: Self::take_child(side, node, self.token) } }; if side == Side::Left { debug_assert_eq!(result.len(self.token), self.index); self.index = 0; } self.describe_self("split_impl (post split)"); // 3. Repeatedly rebalance, until it's balanced => O(log N) iterations each doing O(log N) work. let current_tripod = self.node.take().expect("Non-empty"); self.rebalance_subtree_complete(current_tripod); result } // Internal; sets the tree as the child of the current node. Fixes up indexes and rebalances. // // Leaves the cursor pointing to the root. // // Requirement: there must be not such child. // // Complexity: Time O(log² N), Space O(1). fn set_subtree(&mut self, side: Side, other_root: QuarterNodePtr<'brand, T>) { debug_assert!(self.node.is_some()); debug_assert!(side == Side::Right || self.peek_left().is_none()); debug_assert!(side == Side::Left || self.peek_right().is_none()); self.describe_self("set_subtree (begin)"); let root_tripod = self.node.take().expect("Not empty"); let other_tripod = self.deploy_tripod(&other_root); let other_size = other_tripod.borrow(self.token).size; let current = root_tripod.borrow_mut(self.token).replace_child(side, other_root).expect("Side child - pointing to self"); other_tripod.borrow_mut(self.token).up.replace(current); self.retract_tripod(other_tripod); root_tripod.borrow_mut(self.token).size += other_size; if side == Side::Left { self.index += other_size; } self.rebalance_tree_complete(root_tripod); self.describe_self("set_child (end)"); } // Internal; rebalances the tree up to the root, adjusting the node size as it goes. // // The cursor is left pointing to the root. The index is adjusted accordingly. // // Complexity: Time O(log² N), Space O(1). fn rebalance_tree_complete(&mut self, root_tripod: QuarterNodePtr<'brand, T>) { self.describe_node("rebalance_tree_complete (begin)", &root_tripod); self.rebalance_subtree_complete(root_tripod); // O(log N) iterations of O(log N) complexity. while let Some(_) = self.try_move_up() { self.describe_self("rebalance_tree_complete (loop)"); let root_tripod = self.node.take().expect("Not empty"); self.adjust_size(&root_tripod); self.rebalance_subtree_complete(root_tripod) } self.describe_self("rebalance_tree_complete (end)"); } // Internal; rebalances the tree up to the root, of at most 1 single step, adjusting the node size as it goes. // // The cursor is left pointing to the root. The index is adjusted accordingly. // // Complexity: Time O(log N), Space O(1). fn rebalance_tree_single(&mut self, root_tripod: QuarterNodePtr<'brand, T>) { self.describe_node("rebalance_tree_single (begin)", &root_tripod); self.rebalance_subtree_single(root_tripod); while let Some(_) = self.try_move_up() { self.describe_self("rebalance_tree_single (loop)"); let root_tripod = self.node.take().expect("Not empty"); self.adjust_size(&root_tripod); self.rebalance_subtree_single(root_tripod) } self.describe_self("rebalance_tree_single (end)"); } // Internal; rebalances the current sub-tree, if necessary. // // The cursor is left pointing at the root of the sub-tree, whether it changed or not. The index is adjusted // accordingly. // // Complexity: Time O(log N), Space O(1). fn rebalance_subtree_complete(&mut self, mut root_tripod: QuarterNodePtr<'brand, T>) { self.describe_node("rebalance_subtree_complete (begin)", &root_tripod); let mut previous_index = self.index; loop { self.rebalance_subtree_single(root_tripod); if previous_index == self.index { break; } previous_index = self.index; root_tripod = self.node.take().expect("Non-empty"); self.rebalance_child(Side::Left, &root_tripod); self.rebalance_child(Side::Right, &root_tripod); self.describe_node("rebalance_subtree_complete (loop)", &root_tripod); } self.describe_self("rebalance_subtree_complete (end)"); } // Internal; rebalances the current sub-tree by 1 single step, if necessary. // // The cursor is left pointing at the root of the sub-tree, whether it changed or not. The index is adjusted // accordingly. // // Complexity: Time O(1), Space O(1). fn rebalance_subtree_single(&mut self, root_tripod: QuarterNodePtr<'brand, T>) { debug_assert!(self.node.is_none()); let left_size = root_tripod.borrow(self.token).left_size(self.token); let right_size = root_tripod.borrow(self.token).right_size(self.token); if left_size > 2 * right_size + 1 { let root_tripod = self.prepare_rotation(Side::Left, root_tripod); self.rotate_child_from(Side::Left, root_tripod); } else if right_size > 2 * left_size + 1 { let root_tripod = self.prepare_rotation(Side::Right, root_tripod); self.rotate_child_from(Side::Right, root_tripod); } else { self.node = Some(root_tripod); } } // Internal; rebalances the parent's child on the designated side. // // Complexity: Time O(1), Space O(1). fn rebalance_child(&mut self, side: Side, parent: &GhostNode<'brand, T>) { if let Some(child) = parent.borrow_mut(self.token).take_child(side) { let child_tripod = child.borrow(self.token).deploy(); let child_index = child_tripod.borrow(self.token).index(self.token); let parent_from_child = child_tripod.borrow_mut(self.token).up.take(); let mut tree = TripodTree { root: Some(child) }; let child_tripod = { let mut cursor = CursorMut { token: self.token, tree: &mut tree, node: None, index: child_index }; cursor.rebalance_subtree_single(child_tripod); cursor.node.take().expect("Non-empty") }; let child = tree.root.take().expect("Non-empty"); child.borrow(self.token).retract(child_tripod); child.borrow_mut(self.token).up = parent_from_child; parent.borrow_mut(self.token).set_child(side, child); } } // Internal; swaps the current root of the sub-tree with its child. // // The cursor is left pointing at the former root, the index is adjusted accordingly. // // Invoked with Side::Left: // // Pa Pa // | | // Root Piv // / \ / \ // / \ / \ // Piv X => Root X // / \ / \ // Y Z Y Z // // Invoked with Side::Right: // // Pa Pa // | | // Root Piv // / \ / \ // / \ / \ // X Piv => X Root // / \ / \ // Y Z Y Z // // Legend: // - Pa: Parent, potentially tree.root. // - Root: the current root of the sub-tree. // - Piv: the pivot, or future root of the sub-tree post-rotation. // // Complexity: Time O(1), Space O(1). fn swap_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) { debug_assert!(self.node.is_none()); self.describe_node("swap_child_from (begin)", &root_tripod); let opposite = side.opposite(); // Pick out pivot. let pivot = root_tripod.borrow_mut(self.token).take_child(side).expect("Selected child - otherwise we shouldn't attempt to swap"); let pivot_tripod = self.deploy_tripod(&pivot); self.describe_node("swap_child_from (pivot)", &pivot_tripod); // Swap opposite children, if any. { let opposite_root = root_tripod.borrow_mut(self.token).take_child(opposite); let opposite_pivot = pivot_tripod.borrow_mut(self.token).take_child(opposite); match (opposite_root, opposite_pivot) { (Some(opposite_root), Some(opposite_pivot)) => { let root_from_opposite = opposite_root.borrow_mut(self.token).up.take(); let pivot_from_opposite = opposite_pivot.borrow_mut(self.token).up.take(); opposite_pivot.borrow_mut(self.token).up = root_from_opposite; opposite_root.borrow_mut(self.token).up = pivot_from_opposite; root_tripod.borrow_mut(self.token).set_child(opposite, opposite_pivot); pivot_tripod.borrow_mut(self.token).set_child(opposite, opposite_root); }, (None, Some(opposite_pivot)) => { let root_from_self = root_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("root.opposite == root"); let pivot_from_opposite = opposite_pivot.borrow_mut(self.token).up.replace(root_from_self).expect("pivot.opposite.up == pivot"); root_tripod.borrow_mut(self.token).set_child(opposite, opposite_pivot); pivot_tripod.borrow_mut(self.token).set_child(opposite, pivot_from_opposite); }, (Some(opposite_root), None) => { let pivot_from_self = pivot_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("pivot.opposite == pivot"); let root_from_opposite = opposite_root.borrow_mut(self.token).up.replace(pivot_from_self).expect("root.opposite.up == root"); pivot_tripod.borrow_mut(self.token).set_child(opposite, opposite_root); root_tripod.borrow_mut(self.token).set_child(opposite, root_from_opposite); }, (None, None) => (), } }; // Swap parent. let root_from_pivot = pivot_tripod.borrow_mut(self.token).up.take().expect("pivot.up == root"); let root_from_parent = { let parent_root = root_tripod.borrow_mut(self.token).up.take(); if let Some(parent_root) = parent_root { let parent_side = root_tripod.borrow(self.token).is_child_of(parent_root.borrow(self.token)).expect("Child!"); let root_from_parent = parent_root.borrow_mut(self.token).replace_child(parent_side, pivot).expect("parent.child == root"); pivot_tripod.borrow_mut(self.token).up = Some(parent_root); root_from_parent } else { // root_tripod is root. self.tree.root.replace(pivot).expect("root") } }; // Swap selected child and parent, if any. { let child_pivot = pivot_tripod.borrow_mut(self.token).take_child(side); if let Some(child_pivot) = child_pivot { pivot_tripod.borrow_mut(self.token).set_child(side, root_from_parent); let pivot_from_child = child_pivot.borrow_mut(self.token).up.replace(root_from_pivot).expect("child.up == pivot"); root_tripod.borrow_mut(self.token).set_child(side, pivot_from_child); } else { // Pivot.side pointing to self. let pivot_from_self = pivot_tripod.borrow_mut(self.token).replace_child(side, root_from_parent); root_tripod.borrow_mut(self.token).up = pivot_from_self; root_tripod.borrow_mut(self.token).set_child(side, root_from_pivot); } } self.adjust_size(&root_tripod); self.adjust_size(&pivot_tripod); self.retract_tripod(pivot_tripod); let new_index = { let opposite_pivot_size = root_tripod.borrow(self.token).child_size(opposite, self.token); match side { Side::Left => self.index - 1 - opposite_pivot_size, Side::Right => self.index + 1 + opposite_pivot_size, } }; self.switch_tripod(Some(root_tripod), new_index); self.describe_self("swap_child_from (end)"); } // Internal; rotates the current sub-tree so that the selected child becomes the root. // // The cursor is left pointing at the new root of the sub-tree (pivot), the index is adjusted accordingly. // // Invoked with Side::Left: // // Pa Pa // | | // Root Piv // / \ / \ // / \ / \ // Piv X => Y Root // / \ / \ // Y Piv.OS Piv.OS X // // Invoked with Side::Right: // // Pa Pa // | | // Root Piv // / \ / \ // / \ / \ // X Piv => Root Y // / \ / \ // Piv.OS Y X Piv.OS // // Legend: // - Pa: Parent, potentially tree.root. // - Root: the current root of the sub-tree. // - Piv: the pivot, or future root of the sub-tree post-rotation. // - Piv.OS: the child of the pivot, on the opposite side. // // Complexity: Time O(1), Space O(1). fn rotate_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) { debug_assert!(self.node.is_none()); self.describe_node("rotate_child_from (begin)", &root_tripod); let opposite = side.opposite(); // Pick out pivot. let pivot = root_tripod.borrow_mut(self.token).take_child(side).expect("Selected child - otherwise we shouldn't attempt to rotate"); let pivot_tripod = self.deploy_tripod(&pivot); let root_from_pivot = pivot_tripod.borrow_mut(self.token).up.take().expect("Parent - root!"); debug_assert!(root_tripod.borrow(self.token).is_aliased(Some(&root_from_pivot)), "root == pivot.up"); // Extract pivot pointer from opposite-child up. let pivot_from_opposite_child = { let opposite_child = pivot_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("Either child or pivot-self"); // Aliased => actual self-points to pivot, which didn't have an opposite-side child. let (pivot, child) = if pivot_tripod.borrow(self.token).is_aliased(Some(&opposite_child)) { (opposite_child, root_from_pivot) } else { let pivot = opposite_child.borrow_mut(self.token).up.replace(root_from_pivot).expect("opposite_child.up == pivot"); (pivot, opposite_child) }; debug_assert!(pivot.borrow(self.token).is_aliased(Some(&pivot_tripod)), "pivot.opposite_child.up == pivot"); root_tripod.borrow_mut(self.token).set_child(side, child); pivot }; // Switch pointer-to-root to pointer-to-pivot in parent. let root_from_parent = { let parent = root_tripod.borrow_mut(self.token).up.replace(pivot); if let Some(parent) = parent { let parent_side = root_tripod.borrow(self.token).is_child_of(parent.borrow(self.token)).expect("root.up == parent!"); let result = parent.borrow_mut(self.token).replace_child(parent_side, pivot_from_opposite_child) .expect("parent.parent_side_child == root"); pivot_tripod.borrow_mut(self.token).up = Some(parent); result } else { self.tree.root.replace(pivot_from_opposite_child).expect("tree.root == root") } }; debug_assert!(root_tripod.borrow(self.token).is_aliased(Some(&root_from_parent)), "root == pivot.up"); pivot_tripod.borrow_mut(self.token).set_child(opposite, root_from_parent); self.adjust_size(&root_tripod); self.adjust_size(&pivot_tripod); let index = { // Piv.OS size. let opposite_size = root_tripod.borrow(self.token).child_size(side, self.token); match side { Side::Left => self.index - 1 - opposite_size, Side::Right => self.index + 1 + opposite_size, } }; self.retract_tripod(root_tripod); self.switch_tripod(Some(pivot_tripod), index); self.describe_self("rotate_child_from (end)"); } // Internal; prepare the side child for promotion to root. // // The cursor is not pointing to any element, as the root_tripod is returned. The index is unmodified. // // During the rotation, the pivot opposite side child is moved to be the side child of the root. If this child is // deeper than its sibling, the result is not balanced: // // Root Piv // / \ / \ // / \ / \ // Piv X => Y Root // / \ / \ // Y Piv.OS Piv.OS X // \ \ // A A // // Hence, if necessary, a rotation must be performed to ensure that the pivot "side" child is the root of the // deepest sub-tree prior to doing the main rotation. // // Complexity: Time O(1), Space O(1). fn prepare_rotation(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) -> QuarterNodePtr<'brand, T> { debug_assert!(self.node.is_none()); self.describe_node("prepare_rotation (begin)", &root_tripod); let _original_index = self.index(); let _original_address = &*root_tripod as *const _; let (pivot_selected, pivot_opposite) = { let pivot_node = root_tripod.borrow(self.token).child(side).expect("Pivot!"); let selected = pivot_node.borrow(self.token).child_size(side, self.token); let opposite = pivot_node.borrow(self.token).child_size(side.opposite(), self.token); (selected, opposite) }; if pivot_opposite >= 2 * pivot_selected { self.node = Some(root_tripod); // Move to pivot. match side { Side::Left => self.move_left(), Side::Right => self.move_right(), } let pivot_tripod = self.node.take().expect("Pivot"); self.rotate_child_from(side.opposite(), pivot_tripod); self.move_up(); let root_tripod = self.node.take().expect("Root"); debug_assert_eq!(_original_index, self.index()); debug_assert_eq!(_original_address, &*root_tripod as *const _); self.describe_node("prepare_rotation (end) (modified)", &root_tripod); root_tripod } else { self.describe_node("prepare_rotation (end) (passthrough)", &root_tripod); root_tripod } } // Internal; adjusts the size of the node by adding up the size of its children. // // Complexity: Time O(1), Space O(1). fn adjust_size(&mut self, node: &GhostNode<'brand, T>) { let left_size = node.borrow(self.token).left_size(self.token); let right_size = node.borrow(self.token).right_size(self.token); node.borrow_mut(self.token).size = 1 + left_size + right_size; self.describe_node("adjust_size (adjusted)", node); } // Internal; pops of the specified child, if any, adjusting size and pointers. // // Complexity: Time O(1), Space O(1). fn take_child(side: Side, node: &GhostNode<'brand, T>, token: &mut GhostToken<'brand>) -> Option> { let child = node.borrow_mut(token).take_child(side)?; let node_from_child = child.borrow_mut(token).up.take().expect("child.up == node"); node.borrow_mut(token).set_child(side, node_from_child); let child_size = child.borrow(token).size; node.borrow_mut(token).size -= child_size; Some(child) } } // Debugging code #[allow(dead_code)] impl<'a, 'brand, T> CursorMut<'a, 'brand, T> { // Internal; describe the node: sizes, parent and children, ... #[cfg(all(test, feature = "test-tree-debug"))] fn describe_node(&self, caller: &str, node: &GhostNode<'brand, T>) { let current_size = node.borrow(self.token).size; let left_size = node.borrow(self.token).left_size(self.token); let right_size = node.borrow(self.token).right_size(self.token); eprintln!( "{} - list: {}, index: {}, node: {:?} (size {}), up: {:?}, left: {:?} (size {}), right: {:?} (size {})", caller, self.len(), self.index, node as *const _, current_size, node.borrow(self.token).up.as_ref().map(|node| node as *const _), node.borrow(self.token).left().map(|node| node as *const _), left_size, node.borrow(self.token).right().map(|node| node as *const _), right_size ); } // Internal (dummy) #[cfg(not(all(test, feature = "test-tree-debug")))] fn describe_node(&self, _: &str, _: &GhostNode<'brand, T>) {} // Internal; describe the cursor itself. #[cfg(all(test, feature = "test-tree-debug"))] fn describe_self(&self, caller: &str) { if let Some(node) = self.node.as_ref() { self.describe_node(caller, node); } else { eprintln!( "{} - list: {}, index: {}, current: None", caller, self.len(), self.index ); }; } #[cfg(not(all(test, feature = "test-tree-debug")))] fn describe_self(&self, _: &str) {} } impl<'a, 'brand, T> Drop for CursorMut<'a, 'brand, T> { fn drop(&mut self) { if let Some(tripod) = self.node.take() { super::retract(tripod, self.token); } } } #[cfg(test)] mod tests { use std::ops::Range; use super::super::tests::*; use super::*; #[derive(Clone, Copy)] struct Position<'a> { index: usize, start: usize, end: usize, current: &'a str, up: Option<&'a str>, left: Option<&'a str>, right: Option<&'a str>, prev: Option<&'a str>, next: Option<&'a str>, } impl<'a> Position<'a> { const fn new( index: usize, range: Range, current: &'a str, up: Option<&'a str>, left: Option<&'a str>, right: Option<&'a str>, prev: Option<&'a str>, next: Option<&'a str> ) -> Self { let (start, end) = (range.start, range.end); Self { index, start, end, current, up, left, right, prev, next, } } const fn range(&self) -> Range { self.start..self.end } } #[track_caller] fn assert_twilight(cursor: Cursor<'_, '_, String>) { assert_eq!(None, cursor.index()); assert_eq!(0..0, cursor.range()); assert_eq!(None, cursor.current()); } #[track_caller] fn assert_neighbours(parent: Option<&str>, left: Option<&str>, right: Option<&str>, cursor: Cursor<'_, '_, String>) { assert_eq!(parent, cursor.peek_up().map(String::as_str), "Parent"); assert_eq!(left, cursor.peek_left().map(String::as_str), "Left Child"); assert_eq!(right, cursor.peek_right().map(String::as_str), "Right Child"); } #[track_caller] fn assert_log_neighbours(prev: Option<&str>, next: Option<&str>, cursor: Cursor<'_, '_, String>) { assert_eq!(prev, cursor.peek_prev().map(String::as_str), "Prev"); assert_eq!(next, cursor.peek_next().map(String::as_str), "Next"); } #[track_caller] fn assert_empty(cursor: Cursor<'_, '_, String>) { assert_twilight(cursor); assert_neighbours(None, None, None, cursor); assert_log_neighbours(None, None, cursor); } #[track_caller] fn assert_current(at: usize, range: Range, element: &str, cursor: Cursor<'_, '_, String>) { assert_eq!(Some(at), cursor.index()); assert_eq!(range, cursor.range()); assert_eq!(Some(element), cursor.current().map(String::as_str), "Current"); } #[track_caller] fn assert_position(pos: Position<'_>, cursor: Cursor<'_, '_, String>) { assert_current(pos.index, pos.range(), pos.current, cursor); assert_neighbours(pos.up, pos.left, pos.right, cursor); assert_log_neighbours(pos.prev, pos.next, cursor); } #[track_caller] fn assert_twilight_mut(cursor: &mut CursorMut<'_, '_, String>) { assert_eq!(None, cursor.index()); assert_eq!(0..0, cursor.range()); assert_eq!(None, cursor.current()); } #[track_caller] fn assert_neighbours_mut(parent: Option<&str>, left: Option<&str>, right: Option<&str>, cursor: &CursorMut<'_, '_, String>) { assert_eq!(parent, cursor.peek_up().map(|s| &**s), "Parent"); assert_eq!(left, cursor.peek_left().map(|s| &**s), "Left Child"); assert_eq!(right, cursor.peek_right().map(|s| &**s), "Right Child"); } #[track_caller] fn assert_log_neighbours_mut(prev: Option<&str>, next: Option<&str>, cursor: &CursorMut<'_, '_, String>) { assert_eq!(prev, cursor.peek_prev().map(|s| &**s), "Prev"); assert_eq!(next, cursor.peek_next().map(|s| &**s), "Next"); } #[track_caller] fn assert_empty_mut(cursor: &mut CursorMut<'_, '_, String>) { assert_twilight_mut(cursor); assert_neighbours_mut(None, None, None, cursor); assert_log_neighbours_mut(None, None, cursor); } #[track_caller] fn assert_current_mut(at: usize, range: Range, element: &str, cursor: &mut CursorMut<'_, '_, String>) { assert_eq!(Some(at), cursor.index()); assert_eq!(range, cursor.range()); assert_eq!(Some(element), cursor.current().map(|s| &**s), "Current"); } #[track_caller] fn assert_position_mut(pos: Position<'_>, cursor: &mut CursorMut<'_, '_, String>) { assert_current_mut(pos.index, pos.range(), pos.current, cursor); assert_neighbours_mut(pos.up, pos.left, pos.right, cursor); assert_log_neighbours_mut(pos.prev, pos.next, cursor); } // // Movement. // #[test] fn cursor_empty() { with_tree(&[][..], |token, tree| { let mut cursor = tree.cursor(token); assert_empty(cursor); assert_eq!(None, cursor.try_move_up()); assert_empty(cursor); assert_eq!(None, cursor.try_move_left()); assert_empty(cursor); assert_eq!(None, cursor.try_move_right()); assert_empty(cursor); assert_eq!(None, cursor.try_move_prev()); assert_empty(cursor); assert_eq!(None, cursor.try_move_next()); assert_empty(cursor); assert_eq!(None, cursor.try_move_to(0)); assert_empty(cursor); cursor.move_up(); assert_empty(cursor); cursor.move_left(); assert_empty(cursor); cursor.move_right(); assert_empty(cursor); cursor.move_prev(); assert_empty(cursor); cursor.move_next(); assert_empty(cursor); cursor.move_to(0); assert_empty(cursor); }); } #[test] fn cursor_mut_empty() { with_tree(&[][..], |token, tree| { let mut cursor = tree.cursor_mut(token); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_up()); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_left()); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_right()); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_prev()); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_next()); assert_empty_mut(&mut cursor); assert_eq!(None, cursor.try_move_to(0)); assert_empty_mut(&mut cursor); cursor.move_up(); assert_empty_mut(&mut cursor); cursor.move_left(); assert_empty_mut(&mut cursor); cursor.move_right(); assert_empty_mut(&mut cursor); cursor.move_prev(); assert_empty_mut(&mut cursor); cursor.move_next(); assert_empty_mut(&mut cursor); cursor.move_to(0); assert_empty_mut(&mut cursor); }); } #[test] fn cursor_brush_move_up_left_right() { const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor(token); assert_position(ROOT, cursor); cursor.move_up(); assert_twilight(cursor); cursor.move_left(); assert_position(ROOT, cursor); cursor.move_up(); cursor.move_right(); assert_position(ROOT, cursor); cursor.move_right(); assert_position(RIGHT, cursor); cursor.move_up(); cursor.move_left(); assert_position(LEFT, cursor); cursor.move_right(); assert_position(LR, cursor); cursor.move_right(); assert_twilight(cursor); cursor.move_left(); assert_position(ROOT, cursor); cursor.move_left(); assert_position(LEFT, cursor); cursor.move_left(); assert_twilight(cursor); }); } #[test] fn cursor_mut_brush_move_up_left_right() { const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_mut(token); assert_position_mut(ROOT, &mut cursor); cursor.move_up(); assert_twilight_mut(&mut cursor); cursor.move_left(); assert_position_mut(ROOT, &mut cursor); cursor.move_up(); cursor.move_right(); assert_position_mut(ROOT, &mut cursor); cursor.move_right(); assert_position_mut(RIGHT, &mut cursor); cursor.move_up(); cursor.move_left(); assert_position_mut(LEFT, &mut cursor); cursor.move_right(); assert_position_mut(LR, &mut cursor); cursor.move_right(); assert_twilight_mut(&mut cursor); cursor.move_left(); assert_position_mut(ROOT, &mut cursor); cursor.move_left(); assert_position_mut(LEFT, &mut cursor); cursor.move_left(); assert_twilight_mut(&mut cursor); }); } #[test] fn cursor_brush_move_prev_next() { const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_front(token); for position in &[LEFT, LR, ROOT, RL, RIGHT] { assert_position(*position, cursor); cursor.move_next(); } assert_twilight(cursor); for position in &[RIGHT, RL, ROOT, LR, LEFT] { cursor.move_prev(); assert_position(*position, cursor); } cursor.move_prev(); assert_twilight(cursor); cursor.move_next(); assert_position(LEFT, cursor); cursor = tree.cursor_back(token); assert_position(RIGHT, cursor); }); } #[test] fn cursor_mut_brush_move_prev_next() { const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { { let mut cursor = tree.cursor_front_mut(token); for position in &[LEFT, LR, ROOT, RL, RIGHT] { assert_position_mut(*position, &mut cursor); cursor.move_next(); } assert_twilight_mut(&mut cursor); for position in &[RIGHT, RL, ROOT, LR, LEFT] { cursor.move_prev(); assert_position_mut(*position, &mut cursor); } cursor.move_prev(); assert_twilight_mut(&mut cursor); cursor.move_next(); assert_position_mut(LEFT, &mut cursor); } let mut cursor = tree.cursor_back_mut(token); assert_position_mut(RIGHT, &mut cursor); }); } #[test] fn cursor_brush_move_to() { const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); const POSITIONS: [Position<'static>; 5] = [LEFT, LR, ROOT, RL, RIGHT]; with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor(token); for offset in 0..POSITIONS.len() { cursor.move_to(POSITIONS.len()); assert_twilight(cursor); for base in &[1, 0, 2, 4, 3, 0, 2, 4, 1, 3, 2, 0, 3, 1, 4] { let index = (*base + offset) % POSITIONS.len(); cursor.move_to(index); assert_position(POSITIONS[index], cursor); } } }); } #[test] fn cursor_mut_brush_move_to() { const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); const POSITIONS: [Position<'static>; 5] = [LEFT, LR, ROOT, RL, RIGHT]; with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_mut(token); for offset in 0..POSITIONS.len() { cursor.move_to(POSITIONS.len()); assert_twilight_mut(&mut cursor); for base in &[1, 0, 2, 4, 3, 0, 2, 4, 1, 3, 2, 0, 3, 1, 4] { let index = (*base + offset) % POSITIONS.len(); cursor.move_to(index); assert_position_mut(POSITIONS[index], &mut cursor); } } }); } #[test] fn cursor_mut_move_to_self() { const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR")); const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root")); const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL")); const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R")); const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None); const POSITIONS: [Position<'static>; 5] = [LEFT, LR, ROOT, RL, RIGHT]; // Move to self. with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_mut(token); for index in 0..POSITIONS.len() { cursor.move_to(index); assert_position_mut(POSITIONS[index], &mut cursor); cursor.move_to(index); assert_position_mut(POSITIONS[index], &mut cursor); } cursor.move_to(POSITIONS.len()); assert_twilight_mut(&mut cursor); cursor.move_to(POSITIONS.len()); assert_twilight_mut(&mut cursor); }); } // // Editions // #[test] fn cursor_mut_remove_current_twilight() { with_tree(&[], |token, tree| { let mut cursor = tree.cursor_mut(token); assert_twilight_mut(&mut cursor); let removed = cursor.remove_current(); assert_twilight_mut(&mut cursor); assert_eq!(None, removed); }); with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_mut(token); cursor.move_up(); assert_twilight_mut(&mut cursor); let removed = cursor.remove_current(); assert_eq!(None, removed); assert_twilight_mut(&mut cursor); assert_tree(&["Root", "L", "R", "-", "LR", "RL"], cursor.as_cursor()); }); } #[test] fn cursor_mut_remove_current_root() { with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_mut(token); { const POS: Position<'static> = Position::new(2, 0..4, "R", None, Some("L"), Some("RL"), Some("LR"), Some("RL")); eprintln!("===== Remove Root ====="); let removed = cursor.remove_current(); assert_eq!(Some("Root".to_string()), removed); assert_tree(&["R", "L", "RL", "-", "LR"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(2, 2..3, "RL", Some("L"), None, None, Some("L"), None); eprintln!("===== Remove R ====="); let removed = cursor.remove_current(); assert_eq!(Some("R".to_string()), removed); assert_tree(&["L", "LR", "RL"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(1, 0..2, "RL", None, Some("LR"), None, Some("LR"), None); eprintln!("===== Remove L ====="); cursor.move_up(); let removed = cursor.remove_current(); assert_eq!(Some("L".to_string()), removed); assert_tree(&["RL", "LR"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { eprintln!("===== Remove RL ====="); let removed = cursor.remove_current(); assert_eq!(Some("RL".to_string()), removed); assert_tree(&["LR"], cursor.as_cursor()); assert_twilight(cursor.as_cursor()); } { eprintln!("===== Remove LR ====="); cursor.move_left(); let removed = cursor.remove_current(); assert_eq!(Some("LR".to_string()), removed); assert_tree(&[], cursor.as_cursor()); assert_twilight(cursor.as_cursor()); } }); } #[test] fn cursor_mut_remove_current_front_to_back() { with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_front_mut(token); { const POS: Position<'static> = Position::new(0, 0..1, "LR", Some("Root"), None, None, None, Some("Root")); eprintln!("===== Remove L ====="); let removed = cursor.remove_current(); assert_eq!(Some("L".to_string()), removed); assert_tree(&["Root", "LR", "R", "-", "-", "RL"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(0, 0..1, "Root", Some("RL"), None, None, None, Some("RL")); eprintln!("===== Remove LR ====="); let removed = cursor.remove_current(); assert_eq!(Some("LR".to_string()), removed); assert_tree(&["RL", "Root", "R"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(0, 0..2, "RL", None, None, Some("R"), None, Some("R")); eprintln!("===== Remove Root ====="); let removed = cursor.remove_current(); assert_eq!(Some("Root".to_string()), removed); assert_tree(&["RL", "-", "R"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(0, 0..1, "R", None, None, None, None, None); eprintln!("===== Remove RL ====="); let removed = cursor.remove_current(); assert_eq!(Some("RL".to_string()), removed); assert_tree(&["R"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { eprintln!("===== Remove R ====="); let removed = cursor.remove_current(); assert_eq!(Some("R".to_string()), removed); assert_tree(&[], cursor.as_cursor()); assert_twilight(cursor.as_cursor()); } }); } #[test] fn cursor_mut_remove_current_back_to_front() { with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| { let mut cursor = tree.cursor_back_mut(token); { const POS: Position<'static> = Position::new(3, 3..4, "RL", Some("Root"), None, None, Some("Root"), None); eprintln!("===== Remove R ====="); let removed = cursor.remove_current(); cursor.move_to_back(); assert_eq!(Some("R".to_string()), removed); assert_tree(&["Root", "L", "RL", "-", "LR"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(2, 2..3, "Root", Some("LR"), None, None, Some("LR"), None); eprintln!("===== Remove RL ====="); let removed = cursor.remove_current(); cursor.move_to_back(); assert_eq!(Some("RL".to_string()), removed); assert_tree(&["LR", "L", "Root"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(1, 0..2, "LR", None, Some("L"), None, Some("L"), None); eprintln!("===== Remove Root ====="); let removed = cursor.remove_current(); cursor.move_to_back(); assert_eq!(Some("Root".to_string()), removed); assert_tree(&["LR", "L"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { const POS: Position<'static> = Position::new(0, 0..1, "L", None, None, None, None, None); eprintln!("===== Remove LR ====="); let removed = cursor.remove_current(); cursor.move_to_back(); assert_eq!(Some("LR".to_string()), removed); assert_tree(&["L"], cursor.as_cursor()); assert_position(POS, cursor.as_cursor()); } { eprintln!("===== Remove L ====="); let removed = cursor.remove_current(); assert_eq!(Some("L".to_string()), removed); assert_tree(&[], cursor.as_cursor()); assert_twilight(cursor.as_cursor()); } }); } #[test] fn cursor_mut_insert_after_from_twilight() { const TREES: &[&[&str]] = &[ &["9"], &["9", "8"], &["8", "7", "9"], &["8", "7", "9", "6"], &["8", "6", "9", "5", "7"], &["6", "5", "8", "4", "-", "7", "9"], &["6", "4", "8", "3", "5", "7", "9"], &["6", "4", "8", "3", "5", "7", "9", "2"], &["6", "4", "8", "2", "5", "7", "9", "1", "3"], &["6", "2", "8", "1", "4", "7", "9", "0", "-", "3", "5"] ]; with_tree(&[], |token, tree| { let mut cursor = tree.cursor_mut(token); for (i, tree) in TREES.iter().enumerate() { let element = TREES.len() - i - 1; eprintln!("===== Insert {} =====", element); cursor.insert_after(element.to_string()); assert_tree(tree, cursor.as_cursor()); } }); } #[test] fn cursor_mut_insert_before_from_twilight() { const TREES: &[&[&str]] = &[ &["0"], &["0", "-", "1"], &["1", "0", "2"], &["1", "0", "2", "-", "-", "-", "3"], &["1", "0", "3", "-", "-", "2", "4"], &["3", "1", "4", "0", "2", "-", "5"], &["3", "1", "5", "0", "2", "4", "6"], &["3", "1", "5", "0", "2", "4", "6", "-", "-", "-", "-", "-", "-", "-", "7"], &["3", "1", "5", "0", "2", "4", "7", "-", "-", "-", "-", "-", "-", "6", "8"], &["3", "1", "7", "0", "2", "5", "8", "-", "-", "-", "-", "4", "6", "-", "9"] ]; with_tree(&[], |token, tree| { let mut cursor = tree.cursor_mut(token); for (i, tree) in TREES.iter().enumerate() { eprintln!("===== Insert {} =====", i); cursor.insert_before(i.to_string()); assert_tree(tree, cursor.as_cursor()); } }); } #[test] fn cursor_mut_insert_as_leaf() { // 1 2 3 4 5 6 7 8 9 A B C D E F // 8 // 4 C // 2 6 A E // 1 3 5 7 9 B D F with_tree(&[], |token, tree| { let mut cursor = tree.cursor_mut(token); eprintln!("===== Insert 8 ====="); cursor.insert_after("8".to_string()); assert_tree(&["8"], cursor.as_cursor()); eprintln!("===== Insert 4 & C ====="); cursor.move_to_root(); cursor.insert_before("4".to_string()); cursor.insert_after("C".to_string()); assert_tree(&["8", "4", "C"], cursor.as_cursor()); eprintln!("===== Insert 2 & 6 ====="); cursor.move_left(); cursor.insert_before("2".to_string()); cursor.insert_after("6".to_string()); assert_tree(&["8", "4", "C", "2", "6"], cursor.as_cursor()); eprintln!("===== Insert A & E ====="); cursor.move_to_root(); cursor.move_right(); cursor.insert_before("A".to_string()); cursor.insert_after("E".to_string()); assert_tree(&["8", "4", "C", "2", "6", "A", "E"], cursor.as_cursor()); eprintln!("===== Insert 1 & 3 ====="); cursor.move_to_root(); cursor.move_left(); cursor.move_left(); cursor.insert_before("1".to_string()); cursor.insert_after("3".to_string()); assert_tree(&["8", "4", "C", "2", "6", "A", "E", "1", "3"], cursor.as_cursor()); eprintln!("===== Insert 5 & 7 ====="); cursor.move_to_root(); cursor.move_left(); cursor.move_right(); cursor.insert_before("5".to_string()); cursor.insert_after("7".to_string()); assert_tree(&["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7"], cursor.as_cursor()); eprintln!("===== Insert 9 & B ====="); cursor.move_to_root(); cursor.move_right(); cursor.move_left(); cursor.insert_before("9".to_string()); cursor.insert_after("B".to_string()); assert_tree(&["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B"], cursor.as_cursor()); eprintln!("===== Insert D & F ====="); cursor.move_to_root(); cursor.move_right(); cursor.move_right(); cursor.insert_before("D".to_string()); cursor.insert_after("F".to_string()); assert_tree(&["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"], cursor.as_cursor()); }); } #[test] fn cursor_mut_splice_empty() { const HEX: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; with_tree_duo(&[], &[], |token, tree, splice| { eprintln!("===== Splice After Empty in Empty ====="); { let mut cursor = tree.cursor_mut(token); cursor.splice_after(splice); assert_twilight(cursor.as_cursor()); assert_tree(&[], cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(&[], &[], |token, tree, splice| { eprintln!("===== Splice Before Empty in Empty ====="); { let mut cursor = tree.cursor_mut(token); cursor.splice_before(splice); assert_twilight(cursor.as_cursor()); assert_tree(&[], cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(&[], HEX, |token, tree, splice| { eprintln!("===== Splice After HEX in Empty ====="); { let mut cursor = tree.cursor_mut(token); cursor.splice_after(splice); assert_twilight(cursor.as_cursor()); assert_tree(HEX, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(&[], HEX, |token, tree, splice| { eprintln!("===== Splice Before HEX in Empty ====="); { let mut cursor = tree.cursor_mut(token); cursor.splice_before(splice); assert_twilight(cursor.as_cursor()); assert_tree(HEX, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); } #[test] fn cursor_mut_splice_twilight() { const HEX: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; const FIRST_HALF_HEX: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; const SECOND_HALF_HEX: &[&str] = &["C", "9", "E", "8", "A", "D", "F", "-", "-", "B"]; with_tree_duo(HEX, &[], |token, tree, splice| { eprintln!("===== Splice After Empty in HEX ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); cursor.splice_after(splice); assert_twilight(cursor.as_cursor()); assert_tree(HEX, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(HEX, &[], |token, tree, splice| { eprintln!("===== Splice Before Empty in HEX ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); cursor.splice_before(splice); assert_twilight(cursor.as_cursor()); assert_tree(HEX, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(SECOND_HALF_HEX, FIRST_HALF_HEX, |token, tree, splice| { // 9 // 4 C // 2 6 A E // 1 3 5 8 B - D F // - - - - - - 7 - - - - - - - - - const RESULT: &[&str] = &["9", "4", "C", "2", "6", "A", "E", "1", "3", "5", "8", "B", "-", "D", "F", "-", "-", "-", "-", "-", "-", "7"]; eprintln!("===== Splice After First in Second ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); cursor.splice_after(splice); assert_twilight(cursor.as_cursor()); assert_tree(RESULT, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); with_tree_duo(FIRST_HALF_HEX, SECOND_HALF_HEX, |token, tree, splice| { // 9 // 4 C // 2 6 A E // 1 3 5 7 B - D F // - - - - - - - 8 - - - - - - - - const RESULT: &[&str] = &["9", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "B", "-", "D", "F", "-", "-", "-", "-", "-", "-", "-", "8"]; eprintln!("===== Splice Before Second in First ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); cursor.splice_before(splice); assert_twilight(cursor.as_cursor()); assert_tree(RESULT, cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); } #[test] fn cursor_mut_splice_after() { const ORIGINAL: &[&str] = &["D", "B", "F", "A", "C", "E", "G"]; const SPLICE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; const RESULTS: &[&[&str]] = &[ // 4 // 2 D // A 3 B F // - 1 - - 6 C E G // - - - - - - - - 5 7 - - - - - - &["4", "2", "D", "A", "3", "B", "F", "-", "1", "-", "-", "6", "C", "E", "G", "-", "-", "-", "-", "-", "-", "-", "-", "5", "7"], // 4 // B D // A 2 6 F // - - 1 3 5 C E G // - - - - - - - - - - 7 - - - - - &["4", "B", "D", "A", "2", "6", "F", "-", "-", "1", "3", "5", "C", "E", "G", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "7"], // 4 // C D // B 2 6 F // A - 1 3 5 7 E G &["4", "C", "D", "B", "2", "6", "F", "A", "-", "1", "3", "5", "7", "E", "G"], // 4 // D E // B 2 6 F // A C 1 3 5 7 - G &["4", "D", "E", "B", "2", "6", "F", "A", "C", "1", "3", "5", "7", "-", "G"], // 4 // D F // B 2 6 G // A C E 3 5 7 - - // - - - - - 1 - - - - - - - - - - &["4", "D", "F", "B", "2", "6", "G", "A", "C", "E", "3", "5", "7", "-", "-", "-", "-", "-", "-", "-", "1"], // 4 // D 6 // B F 5 G // A C E 2 - - 7 - // - - - - - - 1 3 - - - - - - - - &["4", "D", "6", "B", "F", "5", "G", "A", "C", "E", "2", "-", "-", "7", "-", "-", "-", "-", "-", "-", "-", "1", "3"], // G // D 4 // B F 2 6 // A C E - 1 3 5 7 &["G", "D", "4", "B", "F", "2", "6", "A", "C", "E", "-", "1", "3", "5", "7"], ]; for index in 0..ORIGINAL.len() { eprintln!("===== Splice After {} =====", index); with_tree_duo(ORIGINAL, SPLICE, |token, tree, splice| { { let mut cursor = tree.cursor_mut(token); cursor.move_to(index); cursor.splice_after(splice); assert_eq!(Some(index), cursor.index()); assert_tree(&RESULTS[index], cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); } } #[test] fn cursor_mut_splice_before() { const ORIGINAL: &[&str] = &["D", "B", "F", "A", "C", "E", "G"]; const SPLICE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; const RESULTS: &[&[&str]] = &[ // A // 4 D // 2 6 B F // 1 3 5 7 - C E G &["A", "4", "D", "2", "6", "B", "F", "1", "3", "5", "7", "-", "C", "E", "G"], // 4 // 2 D // A 3 B F // - 1 - - 6 C E G // - - - - - - - - 5 7 - - - - - - &["4", "2", "D", "A", "3", "B", "F", "-", "1", "-", "-", "6", "C", "E", "G", "-", "-", "-", "-", "-", "-", "-", "-", "5", "7"], // 4 // B D // A 2 6 F // - - 1 3 5 C E G // - - - - - - - - - - 7 - - - - - &["4", "B", "D", "A", "2", "6", "F", "-", "-", "1", "3", "5", "C", "E", "G", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "7"], // 4 // C D // B 2 6 F // A - 1 3 5 7 E G &["4", "C", "D", "B", "2", "6", "F", "A", "-", "1", "3", "5", "7", "E", "G"], // 4 // D E // B 2 6 F // A C 1 3 5 7 - G &["4", "D", "E", "B", "2", "6", "F", "A", "C", "1", "3", "5", "7", "-", "G"], // 4 // D F // B 2 6 G // A C E 3 5 7 - - // - - - - - 1 - - - - - - - - - - &["4", "D", "F", "B", "2", "6", "G", "A", "C", "E", "3", "5", "7", "-", "-", "-", "-", "-", "-", "-", "1"], // 4 // D 6 // B F 5 G // A C E 2 - - 7 - // - - - - - 1 3 - - - - - - - - - &["4", "D", "6", "B", "F", "5", "G", "A", "C", "E", "2", "-", "-", "7", "-", "-", "-", "-", "-", "-", "-", "1", "3"], ]; for index in 0..ORIGINAL.len() { eprintln!("===== Splice Before {} =====", index); with_tree_duo(ORIGINAL, SPLICE, |token, tree, splice| { { let mut cursor = tree.cursor_mut(token); cursor.move_to(index); cursor.splice_before(splice); assert_eq!(Some(index + SPLICE.len()), cursor.index()); assert_tree(&RESULTS[index], cursor.as_cursor()); } assert_tree(&[], splice.cursor(token)); }); } } #[test] fn cursor_mut_split_twilight() { const ORIGINAL: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; with_tree_duo(ORIGINAL, &[], |token, tree, split| { eprintln!("===== Split After ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); *split = cursor.split_after(); assert_twilight(cursor.as_cursor()); assert_tree(&[], cursor.as_cursor()); } assert_tree(ORIGINAL, split.cursor(token)); }); with_tree_duo(ORIGINAL, &[], |token, tree, split| { eprintln!("===== Split Before ====="); { let mut cursor = tree.cursor_mut(token); cursor.move_up(); *split = cursor.split_before(); assert_twilight(cursor.as_cursor()); assert_tree(&[], cursor.as_cursor()); } assert_tree(ORIGINAL, split.cursor(token)); }); } #[test] fn cursor_mut_split_after() { const ORIGINAL: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; const SPLITS: &[(&[&str], &[&str])] = &[ (&["1"], &["8", "4", "C", "2", "6", "A", "E", "-", "3", "5", "7", "9", "B", "D", "F"]), (&["2", "1"], &["8", "4", "C", "3", "6", "A", "E", "-", "-", "5", "7", "9", "B", "D", "F"]), (&["2", "1", "3"], &["8", "6", "C", "4", "7", "A", "E", "-", "5", "-", "-", "9", "B", "D", "F"]), (&["2", "1", "4", "-", "-", "3"], &["8", "6", "C", "5", "7", "A", "E", "-", "-", "-", "-", "9", "B", "D", "F"]), (&["4", "2", "5", "1", "3"], &["C", "8", "E", "6", "A", "D", "F", "-", "7", "9", "B"]), (&["4", "2", "6", "1", "3", "5"], &["C", "8", "E", "7", "A", "D", "F", "-", "-", "9", "B"]), (&["4", "2", "6", "1", "3", "5", "7"], &["C", "8", "E", "-", "A", "D", "F", "-", "-", "9", "B"]), (&["4", "2", "8", "1", "3", "6", "-", "-", "-", "-", "-", "5", "7"], &["C", "A", "E", "9", "B", "D", "F"]), (&["4", "2", "8", "1", "3", "6", "9", "-", "-", "-", "-", "5", "7"], &["C", "A", "E", "-", "B", "D", "F"]), (&["4", "2", "8", "1", "3", "6", "A", "-", "-", "-", "-", "5", "7", "9"], &["C", "B", "E", "-", "-", "D", "F"]), (&["8", "4", "A", "2", "6", "9", "B", "1", "3", "5", "7"], &["E", "C", "F", "-", "D"]), (&["8", "4", "A", "2", "6", "9", "C", "1", "3", "5", "7", "-", "-", "B"], &["E", "D", "F"]), (&["8", "4", "C", "2", "6", "A", "D", "1", "3", "5", "7", "9", "B"], &["E", "-", "F"]), (&["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D"], &["F"]), (ORIGINAL, &[]), ]; for (index, (remainder, castaway)) in SPLITS.iter().enumerate() { eprintln!("===== Split After {} =====", index); with_tree_duo(ORIGINAL, &[], |token, tree, split| { { let mut cursor = tree.cursor_mut(token); cursor.move_to(index); *split = cursor.split_after(); assert_eq!(Some(index), cursor.index()); assert_tree(remainder, cursor.as_cursor()); } assert_tree(castaway, split.cursor(token)); }); } } #[test] fn cursor_mut_split_before() { const ORIGINAL: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; const SPLITS: &[(&[&str], &[&str])] = &[ (ORIGINAL, &[]), (&["8", "4", "C", "2", "6", "A", "E", "-", "3", "5", "7", "9", "B", "D", "F"], &["1"]), (&["8", "4", "C", "3", "6", "A", "E", "-", "-", "5", "7", "9", "B", "D", "F"], &["2", "1"]), (&["8", "6", "C", "4", "7", "A", "E", "-", "5", "-", "-", "9", "B", "D", "F"], &["2", "1", "3"]), (&["8", "6", "C", "5", "7", "A", "E", "-", "-", "-", "-", "9", "B", "D", "F"], &["2", "1", "4", "-", "-", "3"]), (&["C", "8", "E", "6", "A", "D", "F", "-", "7", "9", "B"], &["4", "2", "5", "1", "3"]), (&["C", "8", "E", "7", "A", "D", "F", "-", "-", "9", "B"], &["4", "2", "6", "1", "3", "5"]), (&["C", "8", "E", "-", "A", "D", "F", "-", "-", "9", "B"], &["4", "2", "6", "1", "3", "5", "7"]), (&["C", "A", "E", "9", "B", "D", "F"], &["4", "2", "8", "1", "3", "6", "-", "-", "-", "-", "-", "5", "7"]), (&["C", "A", "E", "-", "B", "D", "F"], &["4", "2", "8", "1", "3", "6", "9", "-", "-", "-", "-", "5", "7"]), (&["C", "B", "E", "-", "-", "D", "F"], &["4", "2", "8", "1", "3", "6", "A", "-", "-", "-", "-", "5", "7", "9"]), (&["E", "C", "F", "-", "D"], &["8", "4", "A", "2", "6", "9", "B", "1", "3", "5", "7"]), (&["E", "D", "F"], &["8", "4", "A", "2", "6", "9", "C", "1", "3", "5", "7", "-", "-", "B"]), (&["E", "-", "F"], &["8", "4", "C", "2", "6", "A", "D", "1", "3", "5", "7", "9", "B"]), (&["F"], &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D"]), ]; for (index, (remainder, castaway)) in SPLITS.iter().enumerate() { eprintln!("===== Split Before {} =====", index); with_tree_duo(ORIGINAL, &[], |token, tree, split| { { let mut cursor = tree.cursor_mut(token); cursor.move_to(index); *split = cursor.split_before(); assert_eq!(Some(0), cursor.index()); assert_tree(remainder, cursor.as_cursor()); } assert_tree(castaway, split.cursor(token)); }); } } } // mod tests ================================================ FILE: src/tripod_tree/iter.rs ================================================ use core::{ mem, ops::Range, }; use ghost_cell::GhostToken; use super::{Cursor, TripodTree}; /// An iterator over a TripodList, self-sufficient once created as it carries its own token. pub struct Iter<'a, 'brand, T> { range: Range, cursor: Cursor<'a, 'brand, T>, } impl<'a, 'brand, T> Iter<'a, 'brand, T> { /// Creates a new instance, iterating over the entire tree. pub fn new(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self { let range = 0..tree.len(token); let cursor = tree.cursor(token); Self { range, cursor, } } /// Creates a new instance, iterating over the specified range of the tree. pub fn range(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>, range: Range) -> Self { let cursor = tree.cursor(token); Self { range, cursor, } } // Internal; converts position to element. fn at(&self, index: usize) -> Option<&'a T> { let mut cursor = self.cursor; cursor.move_to(index); cursor.current() } } impl<'a, 'brand, T> Iterator for Iter<'a, 'brand, T> { type Item = &'a T; fn next(&mut self) -> Option { let next = self.range.next(); next.and_then(|index| self.at(index)) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } fn count(self) -> usize { self.range.count() } fn last(mut self) -> Option { let range = mem::replace(&mut self.range, 0..0); let next = range.last(); next.and_then(|index| self.at(index)) } fn nth(&mut self, n: usize) -> Option { let next = self.range.nth(n); next.and_then(|index| self.at(index)) } } impl<'a, 'brand, T> DoubleEndedIterator for Iter<'a, 'brand, T> { fn next_back(&mut self) -> Option { let next = self.range.next_back(); next.and_then(|index| self.at(index)) } fn nth_back(&mut self, n: usize) -> Option { let next = self.range.nth_back(n); next.and_then(|index| self.at(index)) } } impl<'a, 'brand, T> Clone for Iter<'a, 'brand, T> { fn clone(&self) -> Self { Self { range: self.range.clone(), cursor: self.cursor, } } } #[cfg(test)] mod tests { use super::super::tests::*; const TREE: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; #[test] fn iter_range() { with_tree(TREE, |token, tree| { eprintln!("===== Full Range ====="); let iter = tree.iter_range(.., token); let collected: Vec<&str> = iter.map(String::as_str).collect(); assert_eq!(&["1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][..], collected); }); with_tree(TREE, |token, tree| { eprintln!("===== RangeTo ====="); let iter = tree.iter_range(..7, token); let collected: Vec<&str> = iter.map(String::as_str).collect(); assert_eq!(&["1", "2", "3", "4", "5", "6", "7"][..], collected); }); with_tree(TREE, |token, tree| { eprintln!("===== RangeFrom ====="); let iter = tree.iter_range(7.., token); let collected: Vec<&str> = iter.map(String::as_str).collect(); assert_eq!(&["8", "9", "A", "B", "C", "D", "E", "F"][..], collected); }); with_tree(TREE, |token, tree| { eprintln!("===== Range ====="); let iter = tree.iter_range(5..9, token); let collected: Vec<&str> = iter.map(String::as_str).collect(); assert_eq!(&["6", "7", "8", "9"][..], collected); }); } #[test] fn iter_next() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); let collected: Vec<&str> = iter.map(String::as_str).collect(); assert_eq!(&["1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][..], collected); }); } #[test] fn iter_size_hint() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); assert_eq!((15, Some(15)), iter.size_hint()); }); } #[test] fn iter_count() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); assert_eq!(15, iter.count()); }); } #[test] fn iter_last() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); assert_eq!(Some("F"), iter.last().map(String::as_str)); }); } #[test] fn iter_nth() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); let collected: Vec<&str> = iter.step_by(3).map(String::as_str).collect(); assert_eq!(&["1", "4", "7", "A", "D"][..], collected); }); } #[test] fn iter_next_back() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); let collected: Vec<&str> = iter.rev().map(String::as_str).collect(); assert_eq!(&["F", "E", "D", "C", "B", "A", "9", "8", "7", "6", "5", "4", "3", "2", "1"][..], collected); }); } #[test] fn iter_nth_back() { with_tree(TREE, |token, tree| { let iter = tree.iter(token); let collected: Vec<&str> = iter.rev().step_by(3).map(String::as_str).collect(); assert_eq!(&["F", "C", "9", "6", "3"][..], collected); }); } } // mod tests ================================================ FILE: src/tripod_tree.rs ================================================ //! An Indexed Balanced Binary Tree, with externally supplied token. //! //! The `TripodTree` is building block for Binary Trees, out of the box, it provides: //! //! - Order-Preservation: the relative order of inserted items is preserved throughout mutations. //! - Balancing: the tree is balanced automatically, so that at any point the left-subtree and right-subtree number //! of elements differ by at most a factor of 2. //! - Indexing: each element in the tree is indexed by a number in [0, N), where N is the number of elements, //! according to their order. //! //! The `TripodTree`, however, does not by itself establish any order, it simply preserves the order of insertion. mod cursor; mod iter; pub use cursor::{Cursor, CursorMut}; pub use iter::Iter; use core::{ cell::Cell, cmp, mem, ops::{Bound, Range, RangeBounds}, }; use ghost_cell::{GhostCell, GhostToken}; use static_rc::StaticRc; #[cfg(feature = "experimental-ghost-cursor")] use ghost_cell::GhostCursor; /// A safe implementation of an indexed balanced binary tree. /// /// Each node contains 1 element as well as 4 pointers: up, left, right, and the tripod pointer. pub struct TripodTree<'brand, T> { root: Option>, } impl<'brand, T> TripodTree<'brand, T> { /// Creates a new, empty, instance. pub const fn new() -> Self { Self { root: None, } } /// Creates a new instance, with a single value. pub fn singleton(value: T, token: &mut GhostToken<'brand>) -> Self { Self { root: Some(Self::from_value(value, token)) } } /// Creates an iterator over the entire tree, from front to back. /// /// # Complexity /// /// The complexity of this method itself is O(1). /// /// The complexity of calling `next` on the resulting iterator is O(log N) in the number of elements. pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> { Iter::new(token, self) } /// Creates an iterator over the specified range, from front to back. /// /// If the start bound is greater than the end bound, this is empty. /// /// # Complexity /// /// The complexity of this method itself is O(1). /// /// The complexity of calling `next` on the resulting iterator is O(log N) in the number of elements. pub fn iter_range<'a, R>(&'a self, range: R, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> where R: RangeBounds, { let range = self.into_range(range, token); Iter::range(token, self, range) } /// Creates a cursor pointing to the root element. pub fn cursor<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new(token, self) } /// Creates a mutable cursor pointing to the root element. pub fn cursor_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new(token, self) } /// Creates a cursor pointing to the front element. pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_front(token, self) } /// Creates a mutable cursor pointing to the front element. pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_front(token, self) } /// Creates a cursor pointing to the back element. pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> { Cursor::new_back(token, self) } /// Creates a mutable cursor pointing to the back element. pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> { CursorMut::new_back(token, self) } /// Returns whether the tree is empty, or not. pub fn is_empty(&self) -> bool { self.root.is_none() } /// Returns the number of elements in the tree. pub fn len(&self, token: &GhostToken<'brand>) -> usize { self.root.as_ref().map(|node| node.borrow(token).size).unwrap_or(0) } /// Clears the tree of all elements. /// /// # Complexity /// /// - Time: O(N) in the number of elements. /// - Space: O(1). /// /// Note: if a panic occurs, because dropping an element panics, then the tree is left is an unusable state. pub fn clear(&mut self, token: &mut GhostToken<'brand>) { if let Some(root) = self.root.take() { let mut tripod = root.borrow(token).deploy(); // O(N) iterations, performing O(1) work each. loop { // Clear the left sub-tree first. if let Some(left) = tripod.borrow(token).left() { let left_tripod = left.borrow(token).deploy(); retract(tripod, token); tripod = left_tripod; continue; } // And the right sub-tree afterwards. if let Some(right) = tripod.borrow(token).right() { let right_tripod = right.borrow(token).deploy(); retract(tripod, token); tripod = right_tripod; continue; } // Neither left nor right, time to clean and move up! if let Some(up) = tripod.borrow_mut(token).up.take() { let up_tripod = up.borrow(token).deploy(); let side = tripod.borrow(token).is_child_of(up.borrow(token)).expect("Child!"); let child = up_tripod.borrow_mut(token).replace_child(side, up).expect("Child!"); retract(tripod, token); Self::node_into_inner(child, token); tripod = up_tripod; } else { retract(tripod, token); Self::node_into_inner(root, token); break; } } } } /// Returns a reference to the front element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { let mut cursor = self.cursor(token); cursor.move_to_front(); cursor.current() } /// Returns a reference to the back element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> { let mut cursor = self.cursor(token); cursor.move_to_back(); cursor.current() } /// Returns a reference to the element at the given index, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn at<'a>(&'a self, at: usize, token: &'a GhostToken<'brand>) -> Option<&'a T> { if at >= self.len(token) { return None; } let mut cursor = self.cursor(token); cursor.move_to(at); cursor.current() } /// Pushes an element to the front of the list. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) { let mut cursor = self.cursor_mut(token); cursor.move_to_front(); cursor.insert_before(value); } /// Removes and returns the front element of the list, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option { let mut cursor = self.cursor_mut(token); cursor.move_to_front(); cursor.remove_current() } /// Pushes an element to the back of the list. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) { let mut cursor = self.cursor_mut(token); cursor.move_to_back(); cursor.insert_after(value); } /// Removes and returns the back element of the list, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option { let mut cursor = self.cursor_mut(token); cursor.move_to_back(); cursor.remove_current() } /// Moves all the elements from `other` to the back of the tree, leaving `other` empty. /// /// # Complexity /// /// - Time: O(log N) in the total number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occurs. pub fn append(&mut self, other: &mut TripodTree<'brand, T>, token: &mut GhostToken<'brand>) { let mut cursor = self.cursor_mut(token); cursor.move_to_back(); cursor.splice_after(other); } /// Moves all the elements from `other` to the front of the tree, leaving `other` empty. /// /// # Complexity /// /// - Time: O(log N) in the total number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occurs. pub fn prepend(&mut self, other: &mut TripodTree<'brand, T>, token: &mut GhostToken<'brand>) { let mut cursor = self.cursor_mut(token); cursor.move_to_front(); cursor.splice_before(other); } /// Splits the tree into two at the given index. Returns everything after the given index, including the index. /// /// # Panics /// /// Panics if `at > self.len()`. /// /// # Complexity /// /// - Time: O(log² N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occurs. pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -> TripodTree<'brand, T> { let length = self.len(token); assert!(at <= length, "{} > {}", at, length); let mut result = { let mut cursor = self.cursor_mut(token); cursor.move_to(at); cursor.split_before() }; mem::swap(self, &mut result); result } /// Splits the tree into two according to the given range. Returns everything within the range. /// /// # Complexity /// /// - Time: O(log² N) in the number of elements. /// - Space: O(1). /// /// No memory allocation nor deallocation occurs. pub fn split(&mut self, range: R, token: &mut GhostToken<'brand>) -> TripodTree<'brand, T> where R: RangeBounds, { let length = self.len(token); let range = self.into_range(range, token); // Full Range, well that's easy. if range.start == 0 && range.end == length { return mem::replace(self, TripodTree::new()); } // Until the end. if range.end == length { return self.split_off(range.start, token); } // From the start. if range.start == 0 { let mut result = self.split_off(range.end, token); mem::swap(self, &mut result); return result; } // Interior range. let mut result = self.split_off(range.start, token); let mut after_end = result.split_off(range.end - range.start, token); let mut cursor = self.cursor_mut(token); cursor.move_to_back(); cursor.splice_after(&mut after_end); result } // Internal; constructs a Range suitable for the tree. fn into_range(&self, range: R, token: &GhostToken<'brand>) -> Range where R: RangeBounds, { let length = self.len(token); let start = match range.start_bound() { Bound::Included(n) => cmp::min(*n, length), Bound::Excluded(n) => cmp::min(n.saturating_add(1), length), Bound::Unbounded => 0, }; let end = match range.end_bound() { Bound::Included(n) => cmp::min(n.saturating_add(1), length), Bound::Excluded(n) => cmp::min(*n, length), Bound::Unbounded => length, }; start..end } // Internal; constructs a QuarterNodePtr from a value. fn from_value(value: T, token: &mut GhostToken<'brand>) -> QuarterNodePtr<'brand, T> { let tripod = Cell::new(None); let node = FullNodePtr::new(GhostCell::new(Node { size: 1, value, up: None, left: None, right: None, tripod, })); let halves = FullNodePtr::split::<2, 2>(node); let (up, tripod) = HalfNodePtr::split::<1, 1>(halves.0); let (left, right) = HalfNodePtr::split::<1, 1>(halves.1); up.borrow(token).retract(tripod); up.borrow_mut(token).left = Some(left); up.borrow_mut(token).right = Some(right); up } // Internal; construct a Tree from QuarterNodePtr. fn from_quarter(node: QuarterNodePtr<'brand, T>, token: &GhostToken<'brand>) -> Self { let _node = node.borrow(token); debug_assert!(_node.up.is_none()); debug_assert!(_node.is_aliased(_node.left.as_ref().map(|node| &**node))); debug_assert!(_node.is_aliased(_node.right.as_ref().map(|node| &**node))); Self { root: Some(node), } } // Internal; returns the value contained within. fn node_into_inner(node: QuarterNodePtr<'brand, T>, token: &mut GhostToken<'brand>) -> T { let full = Self::node_into_full(node, token); Self::full_into_inner(full) } // Internal; returns the full pointer. fn node_into_full(node: QuarterNodePtr<'brand, T>, token: &mut GhostToken<'brand>) -> FullNodePtr<'brand, T> { let left = node.borrow_mut(token).left.take().expect("Left child - pointing to self"); let right = node.borrow_mut(token).right.take().expect("Right child - pointing to self"); let tripod = node.borrow_mut(token).tripod.take().expect("Tripod - pointing to self"); let main = HalfNodePtr::join(node, tripod); let children = HalfNodePtr::join(left, right); FullNodePtr::join(main, children) } // Internal; returns the value contained within. fn full_into_inner(full: FullNodePtr<'brand, T>) -> T { let ghost_cell = FullNodePtr::into_inner(full); let node = GhostNode::into_inner(ghost_cell); // If the node still has a prev and next, they are leaked. debug_assert!(node.up.is_none()); debug_assert!(node.left.is_none()); debug_assert!(node.right.is_none()); debug_assert!(node.tripod.replace(None).is_none()); node.value } } #[cfg(feature = "experimental-ghost-cursor")] impl<'brand, T> TripodTree<'brand, T> { /// Returns a mutable reference to the front element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { let root = self.root.as_ref()?; let mut cursor = GhostCursor::new(token, Some(root)); while let Ok(_) = cursor.move_mut(Node::left) {} cursor.into_inner().map(|node| &mut node.value) } /// Returns a mutable reference to the back element, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { let root = self.root.as_ref()?; let mut cursor = GhostCursor::new(token, Some(root)); while let Ok(_) = cursor.move_mut(Node::right) {} cursor.into_inner().map(|node| &mut node.value) } /// Returns a mutable reference to the element at the given index, if any. /// /// # Complexity /// /// - Time: O(log N) in the number of elements. /// - Space: O(1). pub fn at_mut<'a>(&'a mut self, mut at: usize, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> { use cmp::Ordering::*; if at >= self.len(token) { return None; } let root = self.root.as_ref()?; let mut cursor = GhostCursor::new(token, Some(root)); loop { let index = cursor.borrow().map(|node| node.index(cursor.token())).unwrap_or(0); match at.cmp(&index) { Less => cursor.move_mut(Node::left), Equal => break, Greater => { at = at - index - 1; cursor.move_mut(Node::right) }, }.expect("Successful move!"); } cursor.into_inner().map(|node| &mut node.value) } } impl<'brand, T> Default for TripodTree<'brand, T> { fn default() -> Self { Self::new() } } /// The side of a child. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Side { /// The left-side child, all elements on the left-side are "before" the parent node. Left, /// The right-side child, all elements on the right-side are "after" the parent node. Right, } impl Side { /// The opposite side. pub fn opposite(self) -> Side { match self { Side::Left => Side::Right, Side::Right => Side::Left, } } } // // Implementation // struct Node<'brand, T> { // The size of the subtree rooted at this node. size: usize, value: T, up: Option>, left: Option>, right: Option>, tripod: Cell>>, } impl<'brand, T> Node<'brand, T> { // Internal; gives the index of the node in the sub-tree rooted at the node. // // Note: this is the size of the its left sub-tree. fn index(&self, token: &GhostToken<'brand>) -> usize { self.left_size(token) } // Internal; returns the size of the left-subtree. fn left_size(&self, token: &GhostToken<'brand>) -> usize { self.left().map(|node| node.borrow(token).size).unwrap_or(0) } // Internal; returns the size of the right-subtree. fn right_size(&self, token: &GhostToken<'brand>) -> usize { self.right().map(|node| node.borrow(token).size).unwrap_or(0) } // Internal; returns a reference to the right node, if any. fn child_size(&self, side: Side, token: &GhostToken<'brand>) -> usize { // In practice, the child is not, typically, empty, although this property can be violated during manipulations. self.child(side).map(|node| node.borrow(token).size).unwrap_or(0) } // Internal; checks whether a referecen to a node is aliased to another. fn is_aliased(&self, node: Option<&GhostNode<'brand, T>>) -> bool { node.map(|node| self as *const _ as *const u8 == node as *const _ as *const u8).unwrap_or(false) } // Internal; retunrns whether hte node is a child, and on which side. fn is_child(&self, token: &GhostToken<'brand>) -> Option { self.up.as_ref().and_then(|parent| self.is_child_of(parent.borrow(token))) } // Internal; returns whether the node is a child, and which. fn is_child_of(&self, candidate: &Self) -> Option { if self.is_aliased(candidate.left()) { Some(Side::Left) } else if self.is_aliased(candidate.right()) { Some(Side::Right) } else { None } } // Internal; returns a reference to the up node, if any. fn up(&self) -> Option<&GhostNode<'brand, T>> { let result = self.up.as_ref().map(|node| &**node); debug_assert!(!self.is_aliased(result), "self.up never aliases itself"); result } // Internal; returns a reference to the left node, if any. fn left(&self) -> Option<&GhostNode<'brand, T>> { // In practice, the `self.left` is not, typically, empty, although this property can be violated during manipulations. let result = self.left.as_ref().map(|node| &**node); if self.is_aliased(result) { None } else { result } } // Internal; returns a reference to the right node, if any. fn right(&self) -> Option<&GhostNode<'brand, T>> { // In practice, the `self.right` is not, typically, empty, although this property can be violated during manipulations. let result = self.right.as_ref().map(|node| &**node); if self.is_aliased(result) { None } else { result } } // Internal; returns a reference to the right node, if any. fn child(&self, side: Side) -> Option<&GhostNode<'brand, T>> { // In practice, the child is not, typically, empty, although this property can be violated during manipulations. let result = self.child_ref(side).as_ref().map(|node| &**node); if self.is_aliased(result) { None } else { result } } // Internal; replaces the appropriate child. fn replace_child(&mut self, side: Side, new: QuarterNodePtr<'brand, T>) -> Option> { self.child_mut(side).replace(new) } // Internal; sets the appropriate side. Panics if already set. fn set_child(&mut self, side: Side, new: QuarterNodePtr<'brand, T>) { let previous = self.replace_child(side, new); debug_assert!(previous.is_none(), "{:?} already set!", side); } // Internal; takes the appropriate side, if a child. fn take_child(&mut self, side: Side) -> Option> { if let Some(_) = self.child(side) { self.child_mut(side).take() } else { None } } // Internal; returns a reference to the appropriate side. fn child_ref(&self, side: Side) -> &Option> { match side { Side::Left => &self.left, Side::Right => &self.right, } } // Internal; returns a mutable reference to the appropriate side. fn child_mut(&mut self, side: Side) -> &mut Option> { match side { Side::Left => &mut self.left, Side::Right => &mut self.right, } } // Internal; deploys the tripod. fn deploy(&self) -> QuarterNodePtr<'brand, T> { self.tripod.take().expect("Tripod not to be None") } // Internal; retracts the tripod. fn retract(&self, tripod: QuarterNodePtr<'brand, T>) { let previous = self.tripod.replace(Some(tripod)); debug_assert!(previous.is_none()); } } fn retract<'brand, T>(tripod: QuarterNodePtr<'brand, T>, token: &mut GhostToken<'brand>) { let previous = static_rc::lift_with_mut(Some(tripod), token, |tripod, token| { tripod.as_ref().expect("Some").borrow_mut(token).tripod.get_mut() }); debug_assert!(previous.is_none(), "Node should not have any tripod to retract it!"); } type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>; type QuarterNodePtr<'brand, T> = StaticRc, 1, 4>; type HalfNodePtr<'brand, T> = StaticRc, 2, 4>; type FullNodePtr<'brand, T> = StaticRc, 4, 4>; #[cfg(test)] mod tests { use std::panic::{self, AssertUnwindSafe}; use super::*; #[track_caller] pub(super) fn assert_tree(expected: &[&str], cursor: Cursor<'_, '_, String>) { let flat = flatten(cursor); assert_eq!(expected, flat); } #[track_caller] fn assert_element(expected: Option<&str>, actual: Option<&String>) { assert_eq!(expected, actual.map(String::as_str)); } #[cfg(feature = "experimental-ghost-cursor")] #[track_caller] fn assert_element_mut(expected: Option<&str>, actual: Option<&mut String>) { assert_eq!(expected, actual.map(|s| &**s)); } #[test] fn tree_new() { with_tree(&[][..], |token, tree| { assert_tree(&[][..], tree.cursor(token)); }); } #[test] fn tree_test() { let sample = ["Root", "Left", "Right", "LL", "LR", "RL", "RR"]; with_tree(&sample[..], |token, tree| { assert_tree(&sample[..], tree.cursor(token)); }); let holes = ["Root", "Left", "Right", "-", "LR", "RL"]; with_tree(&holes[..], |token, tree| { assert_tree(&holes[..], tree.cursor(token)); }); } #[test] fn tree_access() { const TREE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; with_tree(TREE, |token, tree| { assert_element(Some("1"), tree.front(token)); assert_element(Some("7"), tree.back(token)); assert_element(Some("1"), tree.at(0, token)); assert_element(Some("2"), tree.at(1, token)); assert_element(Some("3"), tree.at(2, token)); assert_element(Some("4"), tree.at(3, token)); assert_element(Some("5"), tree.at(4, token)); assert_element(Some("6"), tree.at(5, token)); assert_element(Some("7"), tree.at(6, token)); assert_element(None, tree.at(7, token)); }); } #[cfg(feature = "experimental-ghost-cursor")] #[test] fn tree_access_mut() { const TREE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; with_tree(TREE, |token, tree| { assert_element_mut(Some("1"), tree.front_mut(token)); assert_element_mut(Some("7"), tree.back_mut(token)); assert_element_mut(Some("1"), tree.at_mut(0, token)); assert_element_mut(Some("2"), tree.at_mut(1, token)); assert_element_mut(Some("3"), tree.at_mut(2, token)); assert_element_mut(Some("4"), tree.at_mut(3, token)); assert_element_mut(Some("5"), tree.at_mut(4, token)); assert_element_mut(Some("6"), tree.at_mut(5, token)); assert_element_mut(Some("7"), tree.at_mut(6, token)); assert_element_mut(None, tree.at_mut(7, token)); }); } #[test] fn tree_pop_push() { const TREE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; with_tree(TREE, |token, tree| { assert_tree(TREE, tree.cursor(token)); assert_eq!(Some("1".to_string()), tree.pop_front(token)); assert_tree(&["4", "2", "6", "-", "3", "5", "7"], tree.cursor(token)); assert_eq!(Some("7".to_string()), tree.pop_back(token)); assert_tree(&["4", "2", "6", "-", "3", "5"], tree.cursor(token)); tree.push_front("1".to_string(), token); assert_tree(&["4", "2", "6", "1", "3", "5"], tree.cursor(token)); tree.push_back("7".to_string(), token); assert_tree(TREE, tree.cursor(token)); }); } #[test] fn tree_append() { const ORIGINAL: &[&str] = &["D", "B", "F", "A", "C", "E", "G"]; const SPLICE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; with_tree_duo(ORIGINAL, SPLICE, |token, tree, splice| { tree.append(splice, token); // G // D 4 // B F 2 6 // A C E - 1 3 5 7 assert_tree(&["G", "D", "4", "B", "F", "2", "6", "A", "C", "E", "-", "1", "3", "5", "7"], tree.cursor(token)); assert_tree(&[], splice.cursor(token)); }); } #[test] fn tree_prepend() { const ORIGINAL: &[&str] = &["D", "B", "F", "A", "C", "E", "G"]; const SPLICE: &[&str] = &["4", "2", "6", "1", "3", "5", "7"]; with_tree_duo(ORIGINAL, SPLICE, |token, tree, splice| { tree.prepend(splice, token); // A // 4 D // 2 6 B F // 1 3 5 7 - C E G assert_tree(&["A", "4", "D", "2", "6", "B", "F", "1", "3", "5", "7", "-", "C", "E", "G"], tree.cursor(token)); assert_tree(&[], splice.cursor(token)); }); } #[test] fn tree_split_off() { const ORIGINAL: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; with_tree_duo(ORIGINAL, &[], |token, tree, split| { *split = tree.split_off(3, token); assert_tree(&["2", "1", "3"], tree.cursor(token)); // 8 // 6 C // 4 7 A E // - 5 - - 9 B D F assert_tree(&["8", "6", "C", "4", "7", "A", "E", "-", "5", "-", "-", "9", "B", "D", "F"], split.cursor(token)); }); } #[test] fn tree_split() { const ORIGINAL: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5", "7", "9", "B", "D", "F"]; with_tree_duo(ORIGINAL, &[], |token, tree, split| { eprintln!("===== Split Across Root ====="); const RANGE: Range = 3..11; *split = tree.split(RANGE, token); // C // 2 E // 1 3 D F assert_tree(&["C", "2", "E", "1", "3", "D", "F"], tree.cursor(token)); // 8 // 6 A // 4 7 9 B // - 5 - - - - - - assert_tree(&["8", "6", "A", "4", "7", "9", "B", "-", "5"], split.cursor(token)); assert_eq!(RANGE.count(), split.len(token)); }); with_tree_duo(ORIGINAL, &[], |token, tree, split| { eprintln!("===== Split Left Sub-Tree ====="); const RANGE: Range = 3..6; *split = tree.split(RANGE, token); // 8 // 2 C // 1 3 A E // - - - 7 9 B D F assert_tree(&["8", "2", "C", "1", "3", "A", "E", "-", "-", "-", "7", "9", "B", "D", "F"], tree.cursor(token)); // 5 // 4 6 assert_tree(&["5", "4", "6"], split.cursor(token)); assert_eq!(RANGE.count(), split.len(token)); }); with_tree_duo(ORIGINAL, &[], |token, tree, split| { eprintln!("===== Split Right Sub-Tree ====="); const RANGE: Range = 8..12; *split = tree.split(RANGE, token); // 4 // 2 8 // 1 3 6 E // - - - - 5 7 D F assert_tree(&["4", "2", "8", "1", "3", "6", "E", "-", "-", "-", "-", "5", "7", "D", "F"], tree.cursor(token)); // A // 9 C // - - B - assert_tree(&["A", "9", "C", "-", "-", "B"], split.cursor(token)); assert_eq!(RANGE.count(), split.len(token)); }); } pub(super) fn with_tree(flat: &[&str], fun: F) -> R where F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodTree<'brand, String>) -> R, { GhostToken::new(|mut token| { let mut tree = inflate(flat, &mut token); let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut tree))); tree.clear(&mut token); result.expect("No Panic") }) } pub(super) fn with_tree_duo(first: &[&str], second: &[&str], fun: F) -> R where F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodTree<'brand, String>, &mut TripodTree<'brand, String>) -> R, { GhostToken::new(|mut token| { let mut first = inflate(first, &mut token); let mut second = inflate(second, &mut token); let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut first, &mut second))); first.clear(&mut token); second.clear(&mut token); result.expect("No Panic") }) } pub(super) fn inflate<'brand>(flat: &[&str], token: &mut GhostToken<'brand>) -> TripodTree<'brand, String> { fn set_child<'brand>( node: &QuarterNodePtr<'brand, String>, side: Side, child: QuarterNodePtr<'brand, String>, token: &mut GhostToken<'brand>) { let child_tripod = child.borrow(token).deploy(); let child_size = child_tripod.borrow(token).size; let current = node.borrow_mut(token).replace_child(side, child); node.borrow_mut(token).size += child_size; child_tripod.borrow_mut(token).up = current; super::retract(child_tripod, token); } fn inflate_impl<'brand>(index: usize, flat: &[&str], token: &mut GhostToken<'brand>) -> Option> { if index >= flat.len() || flat[index].is_empty() || flat[index] == "-" { return None; } let node = TripodTree::from_value(flat[index].to_string(), token); if let Some(left) = inflate_impl(left_child_index(index), flat, token) { set_child(&node, Side::Left, left, token); } if let Some(right) = inflate_impl(right_child_index(index), flat, token) { set_child(&node, Side::Right, right, token); } Some(node) } let mut tree = TripodTree::new(); tree.root = inflate_impl(0, flat, token); tree } pub(super) fn flatten(mut cursor: Cursor<'_, '_, String>) -> Vec { fn set(element: String, index: usize, flat: &mut Vec) { if index >= flat.len() { flat.resize(index + 1, "-".to_string()); } flat[index] = element; } fn flatten_impl(cursor: Cursor<'_, '_, String>, index: usize, flat: &mut Vec) { let size = if let Some(current) = cursor.current() { set(current.clone(), index, flat); cursor.range().len() } else { return; }; let left_size = { let mut clone = cursor; clone.move_left(); flatten_impl(clone, left_child_index(index), flat); clone.range().len() }; let right_size = { let mut clone = cursor; clone.move_right(); flatten_impl(clone, right_child_index(index), flat); clone.range().len() }; assert_eq!( size, 1 + left_size + right_size, "{} (at {:?}) != 1 + {} (at {:?}) + {} (at {:?})", size, cursor.current(), left_size, cursor.peek_left(), right_size, cursor.peek_right() ); } cursor.move_to_root(); let mut flat = vec!(); flatten_impl(cursor, 0, &mut flat); flat } fn left_child_index(index: usize) -> usize { 2 * index + 1 } fn right_child_index(index: usize) -> usize { 2 * index + 2 } } // mod tests