-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Implement hash_map
macro
#144070
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
base: master
Are you sure you want to change the base?
Implement hash_map
macro
#144070
Conversation
This comment has been minimized.
This comment has been minimized.
3d020f6
to
b5692af
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Wouldn't using one of |
I was thinking about
|
All the options i mentioned should be equivalent to let len = 1 $(+ {stringify!($k); 1})*;
let mut map = HashMap::with_capacity(len);
$( map.insert($k, $v); )* HashMap::from([$(($k, $v)),*]) |
I don't think intrinsics make sense here, this is a library type. I think the repeat insert method makes the most sense as it doesn't have the potential stack usage problem of from. Repeat insert is also how extend is implemented under the hood: https://github.com/rust-lang/hashbrown/blob/670213fb32d208759d0331996894e05604de0c18/src/map.rs#L4562. with_capacity definitely makes sense though. You can count the elements like this: https://lukaswirth.dev/tlborm/decl-macros/building-blocks/counting.html |
Oh actually you might be able to use the unstable macro_metavar_expr_count for the counting too, I forgot about that :D |
I would go for the slice length approach, but resolved constantly, which is technically what I'm doing just that instead of making a variable using So probably macro_rules! hash_map {
() => {{
::std::collections::HashMap::new()
}};
( $( $key:expr => $value:expr ),* $(,)? ) => {{
let mut map = ::std::collections::HashMap::with_capacity(
const { [$($crate::hash_map!(@internal count $key)),*].len() }
);
$( map.insert($key, $value); )*
map
}};
(@internal count $i:tt) => {()}
} This would work best if there is some sort of thing inside the standard library so that the last branch is only used internally in an explicit way, which would also filter out the usage inside the second branch. |
You should try this, which I only remembered after posting the first message |
The problem with this is that it would delay stabilization a lot, so I'm not sure, I don't think adding unstable to unstable helps |
You're allowed to use unstable features internally with |
Would it be possible to use EDIT: or rather HashMap::with_capacity_and_hasher(capacity, Default::default()) for specifying capacity. |
Ok, I will check that now |
In this case you're just missing another diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 7055168e0a6..455d0ca9e24 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -383,6 +383,7 @@ macro_rules! dbg {
#[doc(hidden)]
#[macro_export]
#[unstable(feature = "hash_map_internals", issue = "none")]
+#[allow_internal_unstable(hash_map_internals)]
macro_rules! repetition_utils {
(@count $($tokens:tt),*) => {{
[$($crate::repetition_utils!(@replace $tokens => ())),*].len() This makes it work for me. |
This comment has been minimized.
This comment has been minimized.
Done, I added it, let's see if tests run correctly now. By the way, what's the way you test whether tests fail and whether stability is correct locally? Because I would like to do the same instead of relying on running the workflows. I have read some about the |
I can recommend reading this to see how to build and run the compiler with a standard library: https://rustc-dev-guide.rust-lang.org/building/quickstart.html |
(somehow github doesn't show it nicely despite me leaving it as a review comment but i added a comment here in case it got lost in the ui: #144070 (comment)) |
I believe it didn't show up because it was solved, I didn't see the comment at all, If you could re-review the actual documentation, I changed it a bit. |
I see yeah, I left the comment a few minutes ago so it was with the latest state of your changes |
This comment has been minimized.
This comment has been minimized.
Some changes occurred in src/tools/cargo cc @ehuss |
This comment has been minimized.
This comment has been minimized.
effb783
to
bb50dc0
Compare
This comment has been minimized.
This comment has been minimized.
89f4c4b
to
c8d57d1
Compare
This comment has been minimized.
This comment has been minimized.
c8d57d1
to
066023e
Compare
Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
🤔 I wonder how the implementation would compare to doing:
<
$crate::collections::HashMap<_, _, $crate::hash::RandomState>
as
$crate::convert::From<[(_, _); _]>
>::from([
$(
($key, $value)
),+ // empty case still handled as `new()`.
])
Intuitively, doing a batch of .insert()
s does require the map
to go back to a fully usable-from-the-outside state, whereas a direct batched constructor such as From<[(K, V); N]>
does not, so depending on the impl, there might be more room for optimisation with this more direct approach 🤔
$crate::collections::HashMap::new() | ||
}}; | ||
|
||
( $( $key:expr => $value:expr ),* $(,)? ) => {{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very tiny nit 🙂:
( $( $key:expr => $value:expr ),* $(,)? ) => {{ | |
( $( $key:expr => $value:expr ),+ $(,)? ) => {{ |
would make the intent clearer, and also reject hash_map!(,)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense, I suggest addressing this in a follow-up PR
let mut map = $crate::collections::HashMap::with_capacity( | ||
const { $crate::repetition_utils!(@count $($key),*) } | ||
); | ||
$( map.insert($key, $value); )* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$( map.insert($key, $value); )* | |
$( map.insert($key, $value); )+ |
I have checked the |
Thanks for looking into these 🙏 |
I was now checking about this you said, which feels weird, I thought that without recursiveness this wouldn't have a problem, so should I add another PR to the tracking issue? Wait for a comment period? |
Implementation of #144032
Implements the
hash_map
macro understd/src/macros.rs
.