Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/cargo/util/interning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ impl<'a> From<&'a String> for InternedString {

impl From<String> for InternedString {
fn from(item: String) -> Self {
InternedString::new(&item)
let mut cache = interned_storage();
let s = cache.get(item.as_str()).copied().unwrap_or_else(|| {
let s = item.leak();
cache.insert(s);
s
});

InternedString { inner: s }
Comment on lines +49 to +56
Copy link
Contributor

Choose a reason for hiding this comment

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

Without performance data, this falls to being a refactor. My main concern is that we're duplicating the logic for creating an InternedString.

Unsure whether thats sufficient to block this or not. Will think more on this

Copy link
Member

Choose a reason for hiding this comment

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

Another way to handle this is having a Cow variant of new(), and then both new() and from() call it.

Copy link
Author

Choose a reason for hiding this comment

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

I agree, it just looked like an attempted optimisation — the impl for an already-owned String — that wasn't quite complete. I couldn't work out a way to avoid the duplication without allocating on a common path.

Cow would work but turns a statically known property into a runtime check, which might be reasonable, but requires benchmarking to check.

Copy link
Contributor

Choose a reason for hiding this comment

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

Uncertainty about the additional complexity is why this was not done originally.

If we want to make it part of the type system without duplicating the core logic we could do something like:

fn new_inner<S: AsRef<str>>(str: S, make_stat: impl Fn(S) -> &'static str) -> InternedString {
    let mut cache = interned_storage();
    let s = cache.get(str.as_ref()).copied().unwrap_or_else(|| {
        let s = make_stat(str);
        cache.insert(s);
        s
    });
    InternedString { inner: s }
}

I don't know if it's worth the additional complexity.

Copy link
Contributor

Choose a reason for hiding this comment

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

imo cow offers us a fairly clean design and I don't expect the check will impact performance all that much

}
}

Expand Down