Skip to content

Commit eb6edab

Browse files
authored
Merge pull request RustPython#2397 from RustPython/coolreader18/fasthash
Use ahash instead of siphash in a few places
2 parents d2abad5 + 8cdef9e commit eb6edab

25 files changed

+274
-142
lines changed

Cargo.lock

+159-45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bytecode/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license = "MIT"
1111
[dependencies]
1212
bincode = "1.1"
1313
bitflags = "1.1"
14-
lz4_flex = "0.5"
14+
lz4_flex = "0.7"
1515
num-bigint = { version = "0.3", features = ["serde"] }
1616
num-complex = { version = "0.3", features = ["serde"] }
1717
serde = { version = "1.0", features = ["derive"] }

compiler/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ rustpython-ast = { path = "../ast" }
1515
num-complex = { version = "0.3", features = ["serde"] }
1616
num-traits = "0.2"
1717
log = "0.4"
18-
arrayvec = "0.5"
18+
ahash = "0.6"
1919

2020
[dev-dependencies]
2121
rustpython-parser = { path = "../parser" }

compiler/src/compile.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::error::{CompileError, CompileErrorType};
99
use crate::ir::{self, CodeInfo};
1010
pub use crate::mode::Mode;
1111
use crate::symboltable::{make_symbol_table, statements_to_symbol_table, SymbolScope, SymbolTable};
12-
use indexmap::IndexSet;
12+
use crate::IndexSet;
1313
use itertools::Itertools;
1414
use num_complex::Complex64;
1515
use num_traits::ToPrimitive;
@@ -140,10 +140,10 @@ impl Compiler {
140140
blocks: vec![ir::Block::default()],
141141
current_block: bytecode::Label(0),
142142
constants: Vec::new(),
143-
name_cache: IndexSet::new(),
144-
varname_cache: IndexSet::new(),
145-
cellvar_cache: IndexSet::new(),
146-
freevar_cache: IndexSet::new(),
143+
name_cache: IndexSet::default(),
144+
varname_cache: IndexSet::default(),
145+
cellvar_cache: IndexSet::default(),
146+
freevar_cache: IndexSet::default(),
147147
};
148148
Compiler {
149149
code_stack: vec![module_code],
@@ -217,8 +217,8 @@ impl Compiler {
217217
blocks: vec![ir::Block::default()],
218218
current_block: bytecode::Label(0),
219219
constants: Vec::new(),
220-
name_cache: IndexSet::new(),
221-
varname_cache: IndexSet::new(),
220+
name_cache: IndexSet::default(),
221+
varname_cache: IndexSet::default(),
222222
cellvar_cache,
223223
freevar_cache,
224224
};

compiler/src/ir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use indexmap::IndexSet;
1+
use crate::IndexSet;
22
use rustpython_bytecode::{CodeFlags, CodeObject, ConstantData, Instruction, Label, Location};
33

44
pub type BlockIdx = Label;

compiler/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#[macro_use]
66
extern crate log;
77

8+
type IndexMap<K, V> = indexmap::IndexMap<K, V, ahash::RandomState>;
9+
type IndexSet<T> = indexmap::IndexSet<T, ahash::RandomState>;
10+
811
pub mod compile;
912
pub mod error;
1013
pub mod ir;

compiler/src/symboltable.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Inspirational file: https://github.com/python/cpython/blob/master/Python/symtabl
88
*/
99

1010
use crate::error::{CompileError, CompileErrorType};
11-
use indexmap::map::IndexMap;
11+
use crate::IndexMap;
1212
use rustpython_ast::{self as ast, Location};
1313
use std::fmt;
1414

@@ -58,7 +58,7 @@ impl SymbolTable {
5858
typ,
5959
line_number,
6060
is_nested,
61-
symbols: IndexMap::new(),
61+
symbols: IndexMap::default(),
6262
sub_tables: vec![],
6363
}
6464
}

parser/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ num-traits = "0.2"
2020
unic-emoji-char = "0.9"
2121
unic-ucd-ident = "0.9"
2222
unicode_names2 = "0.4"
23+
phf = { version = "0.8", features = ["macros"] }
24+
hashbrown = "0.9"
25+
ahash = "0.6"

parser/src/function.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use ahash::RandomState;
12
use std::collections::HashSet;
23

34
use crate::ast;
@@ -45,7 +46,7 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ast::ArgumentList,
4546
let mut args = vec![];
4647
let mut keywords = vec![];
4748

48-
let mut keyword_names = HashSet::with_capacity(func_args.len());
49+
let mut keyword_names = HashSet::with_capacity_and_hasher(func_args.len(), RandomState::new());
4950
for (name, value) in func_args {
5051
match name {
5152
Some(n) => {

parser/src/lexer.rs

+41-47
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use num_traits::identities::Zero;
1010
use num_traits::Num;
1111
use std::char;
1212
use std::cmp::Ordering;
13-
use std::collections::HashMap;
1413
use std::str::FromStr;
1514
use unic_emoji_char::is_emoji_presentation;
1615
use unic_ucd_ident::{is_xid_continue, is_xid_start};
@@ -66,52 +65,48 @@ pub struct Lexer<T: Iterator<Item = char>> {
6665
chr1: Option<char>,
6766
chr2: Option<char>,
6867
location: Location,
69-
keywords: HashMap<String, Tok>,
7068
}
7169

72-
pub fn get_keywords() -> HashMap<String, Tok> {
73-
let mut keywords: HashMap<String, Tok> = HashMap::new();
74-
70+
pub static KEYWORDS: phf::Map<&'static str, Tok> = phf::phf_map! {
7571
// Alphabetical keywords:
76-
keywords.insert(String::from("..."), Tok::Ellipsis);
77-
keywords.insert(String::from("False"), Tok::False);
78-
keywords.insert(String::from("None"), Tok::None);
79-
keywords.insert(String::from("True"), Tok::True);
80-
81-
keywords.insert(String::from("and"), Tok::And);
82-
keywords.insert(String::from("as"), Tok::As);
83-
keywords.insert(String::from("assert"), Tok::Assert);
84-
keywords.insert(String::from("async"), Tok::Async);
85-
keywords.insert(String::from("await"), Tok::Await);
86-
keywords.insert(String::from("break"), Tok::Break);
87-
keywords.insert(String::from("class"), Tok::Class);
88-
keywords.insert(String::from("continue"), Tok::Continue);
89-
keywords.insert(String::from("def"), Tok::Def);
90-
keywords.insert(String::from("del"), Tok::Del);
91-
keywords.insert(String::from("elif"), Tok::Elif);
92-
keywords.insert(String::from("else"), Tok::Else);
93-
keywords.insert(String::from("except"), Tok::Except);
94-
keywords.insert(String::from("finally"), Tok::Finally);
95-
keywords.insert(String::from("for"), Tok::For);
96-
keywords.insert(String::from("from"), Tok::From);
97-
keywords.insert(String::from("global"), Tok::Global);
98-
keywords.insert(String::from("if"), Tok::If);
99-
keywords.insert(String::from("import"), Tok::Import);
100-
keywords.insert(String::from("in"), Tok::In);
101-
keywords.insert(String::from("is"), Tok::Is);
102-
keywords.insert(String::from("lambda"), Tok::Lambda);
103-
keywords.insert(String::from("nonlocal"), Tok::Nonlocal);
104-
keywords.insert(String::from("not"), Tok::Not);
105-
keywords.insert(String::from("or"), Tok::Or);
106-
keywords.insert(String::from("pass"), Tok::Pass);
107-
keywords.insert(String::from("raise"), Tok::Raise);
108-
keywords.insert(String::from("return"), Tok::Return);
109-
keywords.insert(String::from("try"), Tok::Try);
110-
keywords.insert(String::from("while"), Tok::While);
111-
keywords.insert(String::from("with"), Tok::With);
112-
keywords.insert(String::from("yield"), Tok::Yield);
113-
keywords
114-
}
72+
"..." => Tok::Ellipsis,
73+
"False" => Tok::False,
74+
"None" => Tok::None,
75+
"True" => Tok::True,
76+
77+
"and" => Tok::And,
78+
"as" => Tok::As,
79+
"assert" => Tok::Assert,
80+
"async" => Tok::Async,
81+
"await" => Tok::Await,
82+
"break" => Tok::Break,
83+
"class" => Tok::Class,
84+
"continue" => Tok::Continue,
85+
"def" => Tok::Def,
86+
"del" => Tok::Del,
87+
"elif" => Tok::Elif,
88+
"else" => Tok::Else,
89+
"except" => Tok::Except,
90+
"finally" => Tok::Finally,
91+
"for" => Tok::For,
92+
"from" => Tok::From,
93+
"global" => Tok::Global,
94+
"if" => Tok::If,
95+
"import" => Tok::Import,
96+
"in" => Tok::In,
97+
"is" => Tok::Is,
98+
"lambda" => Tok::Lambda,
99+
"nonlocal" => Tok::Nonlocal,
100+
"not" => Tok::Not,
101+
"or" => Tok::Or,
102+
"pass" => Tok::Pass,
103+
"raise" => Tok::Raise,
104+
"return" => Tok::Return,
105+
"try" => Tok::Try,
106+
"while" => Tok::While,
107+
"with" => Tok::With,
108+
"yield" => Tok::Yield,
109+
};
115110

116111
pub type Spanned = (Location, Tok, Location);
117112
pub type LexResult = Result<Spanned, LexicalError>;
@@ -193,7 +188,6 @@ where
193188
location: Location::new(0, 0),
194189
chr1: None,
195190
chr2: None,
196-
keywords: get_keywords(),
197191
};
198192
lxr.next_char();
199193
lxr.next_char();
@@ -245,8 +239,8 @@ where
245239
}
246240
let end_pos = self.get_pos();
247241

248-
if self.keywords.contains_key(&name) {
249-
Ok((start_pos, self.keywords[&name].clone(), end_pos))
242+
if let Some(tok) = KEYWORDS.get(name.as_str()) {
243+
Ok((start_pos, tok.clone(), end_pos))
250244
} else {
251245
Ok((start_pos, Tok::Name { name }, end_pos))
252246
}

vm/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ itertools = "0.9"
5757
hex = "0.4.0"
5858
hexf-parse = "0.1.0"
5959
indexmap = "1.0.2"
60+
ahash = "0.6"
6061
crc = "^1.0.0"
61-
maplit = "1.0"
6262
bitflags = "1.2.1"
6363
libc = "0.2"
6464
nix = "0.18"

vm/src/builtins/dict.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ impl PyDictRef {
450450

451451
/// Take a python dictionary and convert it to attributes.
452452
pub fn to_attributes(self) -> PyAttributes {
453-
let mut attrs = PyAttributes::new();
453+
let mut attrs = PyAttributes::default();
454454
for (key, value) in self {
455455
let key = pystr::clone_value(&key);
456456
attrs.insert(key, value);

vm/src/builtins/int.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt
908908
vm.to_repr(obj)?,
909909
))),
910910
}
911-
};
911+
}
912912

913913
// test for strings and bytes
914914
if let Some(s) = obj.downcast_ref::<PyStr>() {

vm/src/builtins/pytype.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::common::lock::{
22
PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard, PyRwLockUpgradableReadGuard,
33
PyRwLockWriteGuard,
44
};
5-
use std::collections::{HashMap, HashSet};
5+
use std::collections::HashSet;
66
use std::fmt;
77

88
use super::classmethod::PyClassMethod;
@@ -133,7 +133,7 @@ impl PyType {
133133

134134
pub fn get_attributes(&self) -> PyAttributes {
135135
// Gather all members here:
136-
let mut attributes = PyAttributes::new();
136+
let mut attributes = PyAttributes::default();
137137

138138
for bc in self.iter_mro().rev() {
139139
for (name, value) in bc.attributes.read().iter() {
@@ -791,7 +791,7 @@ pub fn new(
791791
name: &str,
792792
base: PyTypeRef,
793793
bases: Vec<PyTypeRef>,
794-
attrs: HashMap<String, PyObjectRef>,
794+
attrs: PyAttributes,
795795
mut slots: PyTypeSlots,
796796
) -> Result<PyTypeRef, String> {
797797
// Check for duplicates in bases.
@@ -914,8 +914,7 @@ fn best_base(bases: &[PyTypeRef], vm: &VirtualMachine) -> PyResult<PyTypeRef> {
914914

915915
#[cfg(test)]
916916
mod tests {
917-
use super::{linearise_mro, new};
918-
use super::{HashMap, IdProtocol, PyContext, PyTypeRef};
917+
use super::*;
919918

920919
fn map_ids(obj: Result<Vec<PyTypeRef>, String>) -> Result<Vec<usize>, String> {
921920
Ok(obj?.into_iter().map(|x| x.get_id()).collect())
@@ -932,7 +931,7 @@ mod tests {
932931
"A",
933932
object.clone(),
934933
vec![object.clone()],
935-
HashMap::new(),
934+
PyAttributes::default(),
936935
Default::default(),
937936
)
938937
.unwrap();
@@ -941,7 +940,7 @@ mod tests {
941940
"B",
942941
object.clone(),
943942
vec![object.clone()],
944-
HashMap::new(),
943+
PyAttributes::default(),
945944
Default::default(),
946945
)
947946
.unwrap();

vm/src/frozen.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ pub fn map_frozen<'a>(
1919
})
2020
}
2121

22-
pub fn get_module_inits(vm: &VirtualMachine) -> HashMap<String, code::FrozenModule> {
23-
let mut modules = HashMap::new();
22+
pub fn get_module_inits(
23+
vm: &VirtualMachine,
24+
) -> HashMap<String, code::FrozenModule, ahash::RandomState> {
25+
let mut modules = HashMap::default();
2426

2527
macro_rules! ext_modules {
2628
($($t:tt)*) => {

vm/src/function.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::vm::VirtualMachine;
1010
use indexmap::IndexMap;
1111
use itertools::Itertools;
1212
use result_like::impl_option_like;
13-
use std::collections::HashMap;
1413
use std::marker::PhantomData;
1514
use std::ops::RangeInclusive;
1615

@@ -325,9 +324,9 @@ impl<T> KwArgs<T> {
325324
self.0.remove(name)
326325
}
327326
}
328-
impl<T> From<HashMap<String, T>> for KwArgs<T> {
329-
fn from(kwargs: HashMap<String, T>) -> Self {
330-
KwArgs(kwargs.into_iter().collect())
327+
impl<T> std::iter::FromIterator<(String, T)> for KwArgs<T> {
328+
fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
329+
KwArgs(iter.into_iter().collect())
331330
}
332331
}
333332
impl<T> Default for KwArgs<T> {

vm/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ extern crate flamer;
2121
extern crate bitflags;
2222
#[macro_use]
2323
extern crate log;
24-
#[macro_use]
25-
extern crate maplit;
2624
// extern crate env_logger;
2725

2826
#[macro_use]

vm/src/macros.rs

+18
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,21 @@ cfg_if::cfg_if! {
256256
}
257257
}
258258
}
259+
260+
/// A modified version of the hashmap! macro from the maplit crate
261+
macro_rules! hashmap {
262+
(@single $($x:tt)*) => (());
263+
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
264+
265+
(hasher=$hasher:expr, $($key:expr => $value:expr,)+) => { hashmap!(hasher=$hasher, $($key => $value),+) };
266+
(hasher=$hasher:expr, $($key:expr => $value:expr),*) => {
267+
{
268+
let _cap = hashmap!(@count $($key),*);
269+
let mut _map = ::std::collections::HashMap::with_capacity_and_hasher(_cap, $hasher);
270+
$(
271+
let _ = _map.insert($key, $value);
272+
)*
273+
_map
274+
}
275+
};
276+
}

vm/src/pyobject.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub type PyResult<T = PyObjectRef> = Result<T, PyBaseExceptionRef>; // A valid v
6464
/// For attributes we do not use a dict, but a hashmap. This is probably
6565
/// faster, unordered, and only supports strings as keys.
6666
/// TODO: class attributes should maintain insertion order (use IndexMap here)
67-
pub type PyAttributes = HashMap<String, PyObjectRef>;
67+
pub type PyAttributes = HashMap<String, PyObjectRef, ahash::RandomState>;
6868

6969
// TODO: remove this impl
7070
impl fmt::Display for PyObjectRef {

0 commit comments

Comments
 (0)