Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add api get index of child and to insert child at given index. #15

Closed
wants to merge 8 commits into from

Conversation

jessegrosjean
Copy link

No description provided.

@jessegrosjean jessegrosjean changed the title Add api to insert in node's children at a given index. Add api get index of child and to insert child at given index. Oct 3, 2018
@causal-agent
Copy link
Collaborator

Children form a linked list, so "index" isn't really a concept that should apply to them. The crate documentation claims that all methods are constant time and all iterators are linear time, and I'd like to maintain that API. The "correct" solution here would be to have mutable iterators, but of course Rust makes that quite difficult.

@jessegrosjean
Copy link
Author

I understand not wanting "index" in the API, I'm just not sure how to do what I want without it.

The "correct" solution here would be to have mutable iterators, but of course Rust makes that quite difficult.

Is this something that's possible now with existing ego-tree? If so can you give me a hint in how I would use?

My goal is:

  1. I have a NodeMut
  2. I want to insert a new child value at a given index.

I couldn't figure out how to do this using existing high level API no matter what I tried. (I'm new to Rust, so quite possibly just missing something). The only way that I could get it to work was with low level id manipulation, and so that's why I though it was a good candidate for the crate.

@SimonSapin
Copy link
Contributor

Would something like this work?

fn insert_at<T>(parent: NodeMut<T>, index: usize, new_child: T) -> NodeMut<T> {
    if index == 0 {
        return parent.prepend(new_child)  // covers the `first_child().is_none()` case
    }
    let mut child = parent.first_child().unwrap();
    for _ in 1..index {
        child = child.next_sibling().unwrap()
    }
    child.insert_after(new_child)
}

@LoZack19
Copy link
Contributor

Would something like this work?

fn insert_at<T>(parent: NodeMut<T>, index: usize, new_child: T) -> NodeMut<T> {
    if index == 0 {
        return parent.prepend(new_child)  // covers the `first_child().is_none()` case
    }
    let mut child = parent.first_child().unwrap();
    for _ in 1..index {
        child = child.next_sibling().unwrap()
    }
    child.insert_after(new_child)
}

This tries to implement a mutable iterator, but it doesn't quite work. The BC won't let you reassing child, since it was borrowed mutably by next_sibling()

@LoZack19
Copy link
Contributor

I still would not implement this into master, because of what said previously here. We could maybe isolate the new non-constant time funtions, for making sure that whoever uses them is fully aware of the time complexity they require.

@adamreichold
Copy link
Member

adamreichold commented Aug 26, 2024

I think an API organized around a type derived from std's Cursor might be appropriate. We would provide only efficient methods to produce cursor (e.g. to insert before the first child) and user code would have to advance the cursor N times to insert before "index N" making the asymptotics more explicit in the code.

EDIT: Of course, for insertion CursorMut is the relevant role model.

@adamreichold
Copy link
Member

Thinking about this some more, NodeMut basically already is a cursor but the signature of methods like next_sibling is too restrictive. I wonder if we can just provide an alternative signature like

impl<'a, T: 'a> NodeMut<'a, T> {
    pub fn into_next_sibling(self) -> Option<Self> {
        let id = self.node().next_sibling;
        id.map(move |id| unsafe { self.tree.get_unchecked_mut(id) })
    }
}

to make code like that proposed in #15 (comment) work?

@adamreichold
Copy link
Member

I wonder if we can just provide an alternative signature like

Opened #33 as an alternative approach.

@LoZack19
Copy link
Contributor

I really like the approach in #15 (comment), into_* functions are very much needed in NodeMut

@LoZack19 LoZack19 linked an issue Aug 27, 2024 that may be closed by this pull request
@LoZack19 LoZack19 self-assigned this Aug 27, 2024
@cfvescovo
Copy link
Member

Superseded by #33

@cfvescovo cfvescovo closed this Aug 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to insert child at index?
6 participants