-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Entry API equivalent for Sets #1490
Entry API equivalent for Sets #1490
Comments
👍 Needed this today. |
+1 |
+1 and thanks apasel422 for linking my PR and pointing me to this RFC! ;) |
Also needed this today, specifically: let set: HashSet<String> = HashSet::new();
let ... = set.entry("the_key").or_insert(|| String::new("the_key")); |
I had a discussion about this on reddit today, and assumed that because fn get_or_insert(set: &mut HashSet<Key>, key: Key) -> &Key {
let dupe = key.clone();
set.insert(key);
set.get(&dupe).unwrap()
} |
+1 |
I needed this today. It's a shame Rust doesn't have this. Please add it to sets. |
+1, this would allow a safe zero-copy implementation of my makeuniq.rs script. |
For string interning, this is a very useful feature, and I hit into it today. |
Would definitely like to see this! I have a use case where even if the keys don't "matter", it's still useful to "insert a value and get a reference to either the existing value or inserted value". I'm working on an iterator adapter that filters out duplicates, and without an entry API, there's either an unnecessary lookup or an unnecessary clone: struct Dedupe<I: Iterator>
where I::Item: Eq + Hash + Clone {
iter: I,
seen: HashSet<I::Item>
}
impl<I: Iterator> Iterator for Dedupe<I>
where I::Item: Eq + Hash + Clone {
fn next(&mut self) -> Option<Self::Item> {
loop {
let item = self.iter.next()?;
// Alternatively, do a contains() followed by insert()
if self.seen.insert(item.clone()) {
break Some(item);
}
}
}
} With the entry API, you could do: fn next(&mut self) -> Option<Self::Item> {
loop {
if let WasVacant(item) = self.seen.entry(self.iter.next()?) {
break Some(item.clone()); // Clone only on a cache miss
}
}
} Essentially, there's a class of use case where you want to check if an |
+1 |
This happened: rust-lang/hashbrown#342 |
Needed this today for For my specific case, the workaround is: if !set.contains(key) { // N.B., `key` here is a `Borrow<..>` ref.
set.insert(key.clone());
} but this is suboptimal. |
The regular |
Rollup merge of rust-lang#120077 - SUPERCILEX:set-entry, r=Amanieu Add Set entry API See https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/HashSet.3A.3Aentry/near/413224639 and rust-lang#60896 (comment) Closes rust-lang/rfcs#1490
tracking issue for hashset: rust-lang/rust#60896 also, can this issue be reopened, |
See rust-lang/rust#133548 for |
Rollup merge of rust-lang#133548 - cuviper:btreeset-entry-api, r=Mark-Simulacrum Add `BTreeSet` entry APIs to match `HashSet` The following methods are added, along with the corresponding `Entry` implementation. ```rust impl<T, A: Allocator + Clone> BTreeSet<T, A> { pub fn get_or_insert(&mut self, value: T) -> &T where T: Ord, {...} pub fn get_or_insert_with<Q: ?Sized, F>(&mut self, value: &Q, f: F) -> &T where T: Borrow<Q> + Ord, Q: Ord, F: FnOnce(&Q) -> T, {...} pub fn entry(&mut self, value: T) -> Entry<'_, T, A> where T: Ord, {...} } ``` Tracking issue rust-lang#133549 Closes rust-lang/rfcs#1490
By merging RFC 1194, set recovery we have acknowledged that the values of keys "matter". That is, it's reasonable to have an equal key, but want to know about the details of the stored key.
That RFC added
fn get(&T) -> Option<&T>
,take(&T) -> Option<T>
, andreplace(T) -> Option<T>
.However, what if I have an entry-like situation?
Today, this is the best we can do:
Not only do we incur double-lookup (triple-lookup in the insertion case!), we also incur an unconditional Clone even though we already had a by-value key!
Optimally, we could write
What's the entry API for sets? Well, a heck of a lot simpler. The entry API on maps is all about deferred value handling, and that doesn't make sense for sets.
Vacant::insert
andOccupied::insert
don't make sense because we already have the keyOccupied::get_mut
andinto_mut
don't make sense because we don't acknowledge key mutationOccupied::get
andinto_ref
(to mirror into_mut), andremove
are the only ones that make sensereplace()
to explicitly overwrite the old key... or something..?So basically it would be something like
entry(K) -> WasVacant(Entry) | WasOccupied(Entry)
. Critically, you get the same interface no matter what state the world was in, because there's nothing to do in the Vacant case but insert what was already given.Supporting this would probably mean expanding the Entry API to "care about keys".
I haven't thought about the full implications here, and I don't have the bandwidth to write a full RFC at the moment.
The text was updated successfully, but these errors were encountered: