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

New article: VecDeque::resize() optimization #7

Merged
merged 8 commits into from
Jan 30, 2023
Merged

Conversation

Folyd
Copy link
Contributor

@Folyd Folyd commented Dec 23, 2022

No description provided.

@ZhangHanDong
Copy link
Contributor

lgtm

@Folyd
Copy link
Contributor Author

Folyd commented Dec 26, 2022

Hi, @scottmcm, would you mind reviewing my article? Thanks. ❤️

@XeCycle
Copy link

XeCycle commented Dec 27, 2022

Came over this and I'm curious, does repeat_n need an unsafe block at all? Feeling that Option<(NonZeroUsize, T)> may be able to do the same. I looked at the original PR briefly but it did not explain the rationales.

@Folyd
Copy link
Contributor Author

Folyd commented Dec 27, 2022

Came over this and I'm curious, does repeat_n need an unsafe block at all? Feeling that Option<(NonZeroUsize, T)> may be able to do the same. I looked at the original PR briefly but it did not explain the rationales.

Hi, can you explain how Option<(NonZeroUsize, T)> would avoid unnecessary cloning?

@XeCycle
Copy link

XeCycle commented Dec 27, 2022

can you explain how Option<(NonZeroUnsize, T)> would avoid unnecessary cloning?

Created running example at https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fd82d81d0f485acd769c3b0aaeeb5a3b

@XeCycle
Copy link

XeCycle commented Dec 27, 2022

Another version of that next() without unwrap():

    fn next(&mut self) -> Option<Self::Item> {
        let inner = self.0.as_mut()?;
        if let Some(next) = NonZeroUsize::new(inner.0.get() - 1) {
            inner.0 = next;
            Some(inner.1.clone())
        } else {
            Some(self.0.take()?.1)
        }
    }

Godbolt says this can be optimized to 2 branches, which I assume corresponds to 2 special cases for count == 0 and count == 1, i.e. second ? can be elided.

@scottmcm
Copy link

Feeling that Option<(NonZeroUsize, T)> may be able to do the same.

Good question! I actually tried that first. I wasn't able to get it to optimize as nicely, though.

I think it might be because that's essentially (usize, MaybeUninit<T>) -- because None doesn't have a valid value of T -- rather than the (usize, ManuallyDrop<T>) I ended up using. That affects whether it can have a niche, for example (see https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5e8a9b728df0f55dec1975bfad1e4902) and might have some impact on when LLVM can treat the reads as the same, rather than worrying about potential undef.

Definitely give it a shot and see if you can make it work, though! I'd love to get rid of all the unsafe, though thankfully ManuallyDrop's unsafety is one of the easier kinds to deal with.

Copy link

@scottmcm scottmcm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look reasonable to me!

One thing you might consider adding is a bit more about why not cloning is useful. Probably doesn't need to be a huge section, but it might be worth a mention, or an example in which you can tell between different rust versions that something different is happening.

(For extra credit, consider when you might want the buffer to be reused and what code you're write to do that instead.)

@XeCycle
Copy link

XeCycle commented Dec 29, 2022

@scottmcm your playground link tests for Option<Option(NonZeroUsize, String)>>, but we don't need 2 layers of Option. Just Option<(NonZeroUsize, String)> and it will fill the niche: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e3402f532fa99e63a2a951605e9b1c38

@scottmcm
Copy link

@XeCycle I did that on purpose to show the niche behaviour -- you'll notice the RepeatN I checked in doesn't have an Option either, but I did put it in that playground.

The goal is to show that Option<RepeatN<String>> will be the same size as RepeatN<String>.

@XeCycle
Copy link

XeCycle commented Dec 29, 2022

@scottmcm Ahh sorry, missed your point. Thanks a lot, now I get it that you want the RepeatN to have a usable niche if the inner T has one, for use with Option<RepeatN<T>>, but Option<(NonZeroUsize, T)> failed to propagate that. Yes, your design is strictly superior. Maybe worth mentioning in this article?

Co-authored-by: scottmcm <scottmcm@users.noreply.github.com>
@scottmcm
Copy link

Yes, your design is strictly superior.

Rarely is anything strictly 🙂

One thing that the merged implementation doesn't allow is a RepeatN::empty() -- an implementation using the Option approach could do that via None, but there's no way to get a valid-but-unusable ManuallyDrop.

(AKA every niche is also a constraint.)

@Folyd Folyd mentioned this pull request Jan 6, 2023
8 tasks
@Folyd
Copy link
Contributor Author

Folyd commented Jan 7, 2023

I added an alternative section.

One thing you might consider adding is a bit more about why not cloning is useful. Probably doesn't need to be a huge section, but it might be worth a mention, or an example in which you can tell between different rust versions that something different is happening.

I have no idea how to add something about why not cloning is useful. Can you give some suggestions? Thanks. @scottmcm

@Folyd
Copy link
Contributor Author

Folyd commented Jan 26, 2023

Hi, @scottmcm, do you mind giving another review? We plan to release the first issue end of January. 😄

@Folyd Folyd merged commit 30f2a5b into main Jan 30, 2023
@Folyd Folyd deleted the article-vecdeque-resize branch January 30, 2023 11:14
@LCrossman
Copy link
Collaborator

I understood unneccessary cloning will just take up memory, especially if the cloned item is large - is that what @scottmcm meant @Folyd ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants