mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 06:44:16 +00:00
refactor: Move off of IndexMap/HashMap
This dropped 17KB Again, performance shouldn't be too bad as the total number of argument id's passed in by the user shouldn't be huge, with the upper end being 5-15 except for in extreme cases like rustc accepting arguments from cargo via a file.
This commit is contained in:
parent
d441ebbf62
commit
6e7fd6d4bc
8 changed files with 206 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -127,7 +127,6 @@ dependencies = [
|
|||
"clap_derive",
|
||||
"clap_lex",
|
||||
"humantime",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"shlex",
|
||||
|
|
|
@ -63,7 +63,7 @@ debug = ["clap_derive/debug", "dep:backtrace"] # Enables debug messages
|
|||
unstable-doc = ["derive", "cargo", "wrap_help", "env", "unicode", "unstable-replace", "unstable-grouped"] # for docs.rs
|
||||
|
||||
# Used in default
|
||||
std = ["indexmap/std"] # support for no_std in a backwards-compatible way
|
||||
std = [] # support for no_std in a backwards-compatible way
|
||||
color = ["dep:atty", "dep:termcolor"]
|
||||
suggestions = ["dep:strsim"]
|
||||
|
||||
|
@ -89,7 +89,6 @@ clap_lex = { path = "./clap_lex", version = "0.2.2" }
|
|||
bitflags = "1.2"
|
||||
textwrap = { version = "0.15.0", default-features = false, features = [] }
|
||||
unicase = { version = "2.6", optional = true }
|
||||
indexmap = "1.0"
|
||||
strsim = { version = "0.10", optional = true }
|
||||
atty = { version = "0.2", optional = true }
|
||||
termcolor = { version = "1.1.1", optional = true }
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// Std
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fmt;
|
||||
|
@ -20,6 +19,7 @@ use crate::output::fmt::Stream;
|
|||
use crate::output::{fmt::Colorizer, Help, HelpWriter, Usage};
|
||||
use crate::parser::{ArgMatcher, ArgMatches, Parser};
|
||||
use crate::util::ChildGraph;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::{color::ColorChoice, Id, Key};
|
||||
use crate::{Error, INTERNAL_ERROR_MSG};
|
||||
|
||||
|
@ -93,7 +93,7 @@ pub struct Command<'help> {
|
|||
g_settings: AppFlags,
|
||||
args: MKeyMap<'help>,
|
||||
subcommands: Vec<Command<'help>>,
|
||||
replacers: HashMap<&'help str, &'help [&'help str]>,
|
||||
replacers: FlatMap<&'help str, &'help [&'help str]>,
|
||||
groups: Vec<ArgGroup<'help>>,
|
||||
current_help_heading: Option<&'help str>,
|
||||
current_disp_ord: Option<usize>,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// Std
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
@ -10,6 +9,7 @@ use crate::parser::AnyValue;
|
|||
use crate::parser::Identifier;
|
||||
use crate::parser::PendingArg;
|
||||
use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::Id;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
|
@ -46,14 +46,14 @@ impl ArgMatcher {
|
|||
"ArgMatcher::get_global_values: global_arg_vec={:?}",
|
||||
global_arg_vec
|
||||
);
|
||||
let mut vals_map = HashMap::new();
|
||||
let mut vals_map = FlatMap::new();
|
||||
self.fill_in_global_values(global_arg_vec, &mut vals_map);
|
||||
}
|
||||
|
||||
fn fill_in_global_values(
|
||||
&mut self,
|
||||
global_arg_vec: &[Id],
|
||||
vals_map: &mut HashMap<Id, MatchedArg>,
|
||||
vals_map: &mut FlatMap<Id, MatchedArg>,
|
||||
) {
|
||||
for global_arg in global_arg_vec {
|
||||
if let Some(ma) = self.get(global_arg) {
|
||||
|
@ -99,18 +99,18 @@ impl ArgMatcher {
|
|||
}
|
||||
|
||||
pub(crate) fn remove(&mut self, arg: &Id) {
|
||||
self.matches.args.swap_remove(arg);
|
||||
self.matches.args.remove(arg);
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, arg: &Id) -> bool {
|
||||
self.matches.args.contains_key(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn arg_ids(&self) -> indexmap::map::Keys<Id, MatchedArg> {
|
||||
pub(crate) fn arg_ids(&self) -> std::slice::Iter<'_, Id> {
|
||||
self.matches.args.keys()
|
||||
}
|
||||
|
||||
pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
|
||||
pub(crate) fn entry(&mut self, arg: &Id) -> crate::util::Entry<Id, MatchedArg> {
|
||||
self.matches.args.entry(arg.clone())
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,13 @@ use std::fmt::Debug;
|
|||
use std::iter::{Cloned, Flatten, Map};
|
||||
use std::slice::Iter;
|
||||
|
||||
// Third Party
|
||||
use indexmap::IndexMap;
|
||||
|
||||
// Internal
|
||||
use crate::parser::AnyValue;
|
||||
use crate::parser::AnyValueId;
|
||||
use crate::parser::MatchedArg;
|
||||
use crate::parser::MatchesError;
|
||||
use crate::parser::ValueSource;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::{Id, Key};
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
|
@ -68,7 +66,7 @@ pub struct ArgMatches {
|
|||
pub(crate) valid_args: Vec<Id>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) valid_subcommands: Vec<Id>,
|
||||
pub(crate) args: IndexMap<Id, MatchedArg>,
|
||||
pub(crate) args: FlatMap<Id, MatchedArg>,
|
||||
pub(crate) subcommand: Option<Box<SubCommand>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::output::fmt::Stream;
|
|||
use crate::output::Usage;
|
||||
use crate::parser::{ArgMatcher, ParseState};
|
||||
use crate::util::ChildGraph;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
@ -383,7 +384,7 @@ impl<'help, 'cmd> Validator<'help, 'cmd> {
|
|||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
struct Conflicts {
|
||||
potential: std::collections::HashMap<Id, Vec<Id>>,
|
||||
potential: FlatMap<Id, Vec<Id>>,
|
||||
}
|
||||
|
||||
impl Conflicts {
|
||||
|
|
190
src/util/flat_map.rs
Normal file
190
src/util/flat_map.rs
Normal file
|
@ -0,0 +1,190 @@
|
|||
use std::borrow::Borrow;
|
||||
|
||||
/// Flat (Vec) backed map
|
||||
///
|
||||
/// This preserves insertion order
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct FlatMap<K, V> {
|
||||
keys: Vec<K>,
|
||||
values: Vec<V>,
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> FlatMap<K, V> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, key: K, mut value: V) -> Option<V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
std::mem::swap(&mut self.values[index], &mut value);
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
self.keys.push(key);
|
||||
self.values.push(value);
|
||||
None
|
||||
}
|
||||
|
||||
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
for existing in &self.keys {
|
||||
if existing.borrow() == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
let index = self
|
||||
.keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, k)| (k.borrow() == key).then(|| i))?;
|
||||
self.keys.remove(index);
|
||||
Some(self.values.remove(index))
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
return Entry::Occupied(OccupiedEntry { v: self, index });
|
||||
}
|
||||
}
|
||||
Entry::Vacant(VacantEntry { v: self, key })
|
||||
}
|
||||
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&mut self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> std::slice::Iter<'_, K> {
|
||||
self.keys.iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut {
|
||||
keys: self.keys.iter_mut(),
|
||||
values: self.values.iter_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> Default for FlatMap<K, V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
keys: Default::default(),
|
||||
values: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Entry<'a, K: 'a, V: 'a> {
|
||||
Vacant(VacantEntry<'a, K, V>),
|
||||
Occupied(OccupiedEntry<'a, K, V>),
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default);
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default());
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VacantEntry<'a, K: 'a, V: 'a> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
key: K,
|
||||
}
|
||||
|
||||
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, K: 'a, V: 'a> {
|
||||
keys: std::slice::IterMut<'a, K>,
|
||||
values: std::slice::IterMut<'a, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next() {
|
||||
Some(k) => {
|
||||
let v = self.values.next().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.keys.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next_back() {
|
||||
Some(k) => {
|
||||
let v = self.values.next_back().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {}
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(clippy::single_component_path_imports)]
|
||||
|
||||
mod flat_map;
|
||||
mod flat_set;
|
||||
mod fnv;
|
||||
mod graph;
|
||||
|
@ -8,6 +9,8 @@ mod str_to_bool;
|
|||
|
||||
pub use self::fnv::Key;
|
||||
|
||||
pub(crate) use self::flat_map::Entry;
|
||||
pub(crate) use self::flat_map::FlatMap;
|
||||
pub(crate) use self::flat_set::FlatSet;
|
||||
pub(crate) use self::str_to_bool::str_to_bool;
|
||||
pub(crate) use self::str_to_bool::FALSE_LITERALS;
|
||||
|
|
Loading…
Reference in a new issue