From 89bae0e95f2b189f261caaca2b84ea56400c2382 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Wed, 3 Oct 2018 10:28:57 -0400 Subject: [PATCH 1/6] Add api to insert in node's children at a given index. --- src/lib.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ tests/node_mut.rs | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) mode change 100644 => 100755 tests/node_mut.rs diff --git a/src/lib.rs b/src/lib.rs index 4a4ad23..92d3b42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,6 +274,16 @@ impl<'a, T: 'a> NodeMut<'a, T> { self.prepend_id(id) } + /// Insert a new child into this node at given index. + /// + /// # Panics + /// + /// Panics if `index` is not valid. + pub fn insert(&mut self, value: T, index: usize) -> NodeMut { + let id = self.tree.orphan(value).id; + self.insert_id(id, index) + } + /// Inserts a new sibling before this node. /// /// # Panics @@ -356,6 +366,53 @@ impl<'a, T: 'a> NodeMut<'a, T> { unsafe { self.tree.get_unchecked_mut(new_child_id) } } + /// Insert a child into this node at given index. + /// + /// # Panics + /// + /// Panics if `new_child_id` or `index` are not valid. + pub fn insert_id(&mut self, new_child_id: NodeId, index: usize) -> NodeMut { + if index == 0 { + return self.prepend_id(new_child_id) + } + + assert!(self.has_children(), "invalid index: {}", index); + + let prev_child_id; + let next_child_id; + + unsafe { + let mut children = self.tree.get_unchecked(self.id).children(); + prev_child_id = children.nth(index - 1).map(|n| n.id).unwrap(); + next_child_id = children.next().map(|n| n.id); + } + + { + let mut new_child = self.tree.get_mut(new_child_id).unwrap(); + new_child.detach(); + new_child.node().parent = Some(self.id); + new_child.node().prev_sibling = Some(prev_child_id); + new_child.node().next_sibling = next_child_id; + } + + unsafe { self.tree.node_mut(prev_child_id).next_sibling = Some(new_child_id); } + + if let Some(id) = next_child_id { + unsafe { self.tree.node_mut(id).prev_sibling = Some(new_child_id); } + } + + { + if let Some((first_child_id, last_child_id)) = self.node().children { + let last_child_id = next_child_id.map_or(new_child_id, |_| last_child_id); + self.node().children = Some((first_child_id, last_child_id)); + } else { + self.node().children = Some((new_child_id, new_child_id)); + } + } + + unsafe { self.tree.get_unchecked_mut(new_child_id) } + } + /// Prepends a child to this node. /// /// # Panics diff --git a/tests/node_mut.rs b/tests/node_mut.rs old mode 100644 new mode 100755 index 6625763..e75c3aa --- a/tests/node_mut.rs +++ b/tests/node_mut.rs @@ -199,6 +199,47 @@ fn prepend_3() { assert_eq!(None, d.next_sibling()); } +#[test] +fn insert() { + let mut tree = tree!('a'); + tree.root_mut().insert('c', 0); + tree.root_mut().insert('b', 0); + tree.root_mut().insert('d', 2); + + let root = tree.root(); + let b = root.first_child().unwrap(); + let c = b.next_sibling().unwrap(); + let d = root.last_child().unwrap(); + + assert_eq!(&'b', b.value()); + assert_eq!(&'c', c.value()); + assert_eq!(&'d', d.value()); + assert_eq!(Some(root), b.parent()); + assert_eq!(Some(root), c.parent()); + assert_eq!(Some(root), d.parent()); + assert_eq!(None, b.prev_sibling()); + assert_eq!(Some(c), b.next_sibling()); + assert_eq!(Some(b), c.prev_sibling()); + assert_eq!(Some(d), c.next_sibling()); + assert_eq!(Some(c), d.prev_sibling()); + assert_eq!(None, d.next_sibling()); +} + +#[test] +#[should_panic] +fn insert_should_panic_1() { + let mut tree = tree!('a'); + tree.root_mut().insert('b', 1); +} + +#[test] +#[should_panic] +fn insert_should_panic_2() { + let mut tree = tree!('a'); + tree.root_mut().insert('b', 0); + tree.root_mut().insert('c', 2); +} + #[test] fn insert_before_first() { let mut tree = tree!('a' => { 'c' }); From 9d58b08fdfa4db15064d8eec686d80addc0a046b Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Wed, 3 Oct 2018 11:47:02 -0400 Subject: [PATCH 2/6] Add api to get index of given child. --- src/lib.rs | 14 ++++++++++++-- tests/node_ref.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 92d3b42..63d35b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,6 +201,16 @@ impl<'a, T: 'a> NodeRef<'a, T> { self.node.children.map(|(_, id)| unsafe { self.tree.get_unchecked(id) }) } + /// Returns the index of the given child or None if child doesn't exist. + pub fn index_of_child(&self, child: &NodeRef) -> Option { + for (i, ref each) in self.children().enumerate() { + if each == child { + return Some(i) + } + } + None + } + /// Returns true if this node has siblings. pub fn has_siblings(&self) -> bool { self.node.prev_sibling.is_some() || self.node.next_sibling.is_some() @@ -373,7 +383,7 @@ impl<'a, T: 'a> NodeMut<'a, T> { /// Panics if `new_child_id` or `index` are not valid. pub fn insert_id(&mut self, new_child_id: NodeId, index: usize) -> NodeMut { if index == 0 { - return self.prepend_id(new_child_id) + return self.prepend_id(new_child_id) } assert!(self.has_children(), "invalid index: {}", index); @@ -386,7 +396,7 @@ impl<'a, T: 'a> NodeMut<'a, T> { prev_child_id = children.nth(index - 1).map(|n| n.id).unwrap(); next_child_id = children.next().map(|n| n.id); } - + { let mut new_child = self.tree.get_mut(new_child_id).unwrap(); new_child.detach(); diff --git a/tests/node_ref.rs b/tests/node_ref.rs index ad05b7a..102b728 100644 --- a/tests/node_ref.rs +++ b/tests/node_ref.rs @@ -40,6 +40,18 @@ fn last_child() { assert_eq!(&'c', tree.root().last_child().unwrap().value()); } +#[test] +fn index_of_child() { + let tree = tree!('a' => { 'b', 'c' }); + let root = tree.root(); + let b = root.first_child().unwrap(); + let c = root.last_child().unwrap(); + + assert_eq!(0, root.index_of_child(&b).unwrap()); + assert_eq!(1, root.index_of_child(&c).unwrap()); + assert!(root.index_of_child(&root).is_none()); +} + #[test] fn has_siblings() { let tree = tree!('a' => { 'b', 'c' }); From e3226519b1f76c15a6b0cf9e5958490b34c727ea Mon Sep 17 00:00:00 2001 From: LoZack19 Date: Fri, 23 Aug 2024 14:04:56 +0200 Subject: [PATCH 3/6] reusing logic from insert_id_after to implement insert_id --- src/lib.rs | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 63d35b5..99956b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,8 +283,9 @@ impl<'a, T: 'a> NodeMut<'a, T> { let id = self.tree.orphan(value).id; self.prepend_id(id) } - + /// Insert a new child into this node at given index. + /// This function may take up to linear time in worst case scenarios. /// /// # Panics /// @@ -377,6 +378,7 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Insert a child into this node at given index. + /// This function may take up to linear time in worst case scenarios. /// /// # Panics /// @@ -386,40 +388,17 @@ impl<'a, T: 'a> NodeMut<'a, T> { return self.prepend_id(new_child_id) } - assert!(self.has_children(), "invalid index: {}", index); - - let prev_child_id; - let next_child_id; - - unsafe { - let mut children = self.tree.get_unchecked(self.id).children(); - prev_child_id = children.nth(index - 1).map(|n| n.id).unwrap(); - next_child_id = children.next().map(|n| n.id); - } - - { - let mut new_child = self.tree.get_mut(new_child_id).unwrap(); - new_child.detach(); - new_child.node().parent = Some(self.id); - new_child.node().prev_sibling = Some(prev_child_id); - new_child.node().next_sibling = next_child_id; - } - - unsafe { self.tree.node_mut(prev_child_id).next_sibling = Some(new_child_id); } - - if let Some(id) = next_child_id { - unsafe { self.tree.node_mut(id).prev_sibling = Some(new_child_id); } - } - - { - if let Some((first_child_id, last_child_id)) = self.node().children { - let last_child_id = next_child_id.map_or(new_child_id, |_| last_child_id); - self.node().children = Some((first_child_id, last_child_id)); - } else { - self.node().children = Some((new_child_id, new_child_id)); - } - } + let mut pre_sibling: NodeMut = unsafe { + self.tree + .get_unchecked(self.id) + .children() + .nth(index - 1) // worst case O(n) + .map(|node| node.id) + .map(|id| self.tree.get_unchecked_mut(id)) + .expect(format!("No child found at index {}", index-1).as_str()) + }; + pre_sibling.insert_id_after(new_child_id); unsafe { self.tree.get_unchecked_mut(new_child_id) } } From deb3c6dd199fc983d176a9971acd6644262faf44 Mon Sep 17 00:00:00 2001 From: LoZack19 Date: Fri, 23 Aug 2024 14:12:06 +0200 Subject: [PATCH 4/6] make index_of_child more idiomatic --- src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 99956b0..05fdf1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,13 +202,12 @@ impl<'a, T: 'a> NodeRef<'a, T> { } /// Returns the index of the given child or None if child doesn't exist. + /// This function may take up to linear time in worst case scenarios. pub fn index_of_child(&self, child: &NodeRef) -> Option { - for (i, ref each) in self.children().enumerate() { - if each == child { - return Some(i) - } - } - None + self.children() + .enumerate() + .find(|(_, each)| each == child) + .map(|(i, _)| i) } /// Returns true if this node has siblings. From 46628c21f5d2a36e7bdec2fbed2ee8afcafdbb1b Mon Sep 17 00:00:00 2001 From: LoZack19 Date: Fri, 23 Aug 2024 14:18:07 +0200 Subject: [PATCH 5/6] fix formatting and clippy warnings --- src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e5a34e0..2b0d214 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -373,7 +373,7 @@ impl<'a, T: 'a> NodeMut<'a, T> { let id = self.tree.orphan(value).id; self.prepend_id(id) } - + /// Insert a new child into this node at given index. /// This function may take up to linear time in worst case scenarios. /// @@ -493,17 +493,17 @@ impl<'a, T: 'a> NodeMut<'a, T> { /// Panics if `new_child_id` or `index` are not valid. pub fn insert_id(&mut self, new_child_id: NodeId, index: usize) -> NodeMut { if index == 0 { - return self.prepend_id(new_child_id) + return self.prepend_id(new_child_id); } let mut pre_sibling: NodeMut = unsafe { self.tree - .get_unchecked(self.id) - .children() - .nth(index - 1) // worst case O(n) - .map(|node| node.id) - .map(|id| self.tree.get_unchecked_mut(id)) - .expect(format!("No child found at index {}", index-1).as_str()) + .get_unchecked(self.id) + .children() + .nth(index - 1) // worst case O(n) + .map(|node| node.id) + .map(|id| self.tree.get_unchecked_mut(id)) + .unwrap_or_else(|| panic!("No child found at index {}", index - 1)) }; pre_sibling.insert_id_after(new_child_id); From 7a837c11d7e566de04cb91ac085831afc3f0562d Mon Sep 17 00:00:00 2001 From: LoZack19 Date: Fri, 23 Aug 2024 14:20:17 +0200 Subject: [PATCH 6/6] fix formatting in tests --- tests/node_ref.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/node_ref.rs b/tests/node_ref.rs index 099e866..490015c 100644 --- a/tests/node_ref.rs +++ b/tests/node_ref.rs @@ -46,7 +46,7 @@ fn index_of_child() { let root = tree.root(); let b = root.first_child().unwrap(); let c = root.last_child().unwrap(); - + assert_eq!(0, root.index_of_child(&b).unwrap()); assert_eq!(1, root.index_of_child(&c).unwrap()); assert!(root.index_of_child(&root).is_none());