-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Make vec!() macro create a vector with precise capacity #16204
Conversation
I'll review the code later, but just going by the description, we haven't done this precisely because of the issue of introducing a new macro that isn't necessarily a good design. There's an RFC I filed (can't look up the number now) that modifies the macro system to, among other things, provide counting. I encourage you to find and read through it. |
/// comma-separated expression parameters passed to it. | ||
#[macro_export] | ||
macro_rules! count_args( | ||
($e:expr $(,$e_rest:expr)*) => (1u + count_args!($($e_rest),*)); |
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.
This pattern looks weird, shouldn't it be ($e:expr, $(e_rest: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.
That doesn't work with one argument i.e. count_args!(foo)
.
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.
Ah. You can always add a one-argument case though. But I suppose if this pattern works, then it doesn't matter.
Yeah, this is basically what I thought. It's a macro that only works for The RFC I mentioned is rust-lang/rfcs#88, which introduces new syntax for counting repetitions directly into the macro parser. That avoids the need for a new macro (which is only useful to other macros), supports all nonterminal kinds, and produces a single literal instead of an expression. |
It's possible to avoid a separate macro by being a little creative: /// Create a `std::vec::Vec` containing the arguments.
#[macro_export]
macro_rules! vec(
($($e:expr),*) => ({
// leading _ to allow empty construction without a warning.
let mut _temp = ::std::vec::Vec::with_capacity(vec!(c: $($e),*));
$(_temp.push($e);)*
_temp
});
($($e:expr),+,) => (vec!($($e),+));
// These syntactic forms are for internal use only
(c: $e:expr $(,$e_rest:expr)*) => (1 + vec!(c: $($e_rest),*));
(c: ) => (0);
(c: $($e:expr),*,) => (vec!(c: $($e),*))
) Of course, this requires consumers to abstain from using the internal syntactic forms themselves. I'm guessing this optimization is not pressing enough to justify a hacky interim solution pending the adoption of an RFC like the one you mentioned, so I'll close the PR. |
@bkoropoff Yeah that internal format is also something that's been suggested before. My personal belief is that it's not pressing enough to warrant doing things like that. Hopefully the RFC will be accepted. If not, then we can consider workarounds. |
This seemed like a small but obvious optimization. Feedback questions: