diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..5e43570 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-24 - Avoid vec! for constant collections in initialization loops +**Learning:** Initializing maps/operator managers by iterating over `vec![...]` causes unnecessary heap allocations. Using array literals `[...]` is significantly more efficient since the size is known at compile time and the arrays can be stack-allocated or embedded directly into the binary. +**Action:** Always prefer iterating over array literals instead of `vec![...]` for statically known collections, especially in hot paths or initialization loops. diff --git a/benches/display_expression.rs b/benches/display_expression.rs index f9d04d1..5bcd457 100644 --- a/benches/display_expression.rs +++ b/benches/display_expression.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, Criterion, black_box}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use expression_engine::{parse_expression, ExprAST}; fn bench_display_expression(c: &mut Criterion) { diff --git a/src/operator.rs b/src/operator.rs index 586cc9e..4d60616 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -57,7 +57,8 @@ impl InfixOpManager { use InfixOpType::*; self.register("=", 20, SETTER, RIGHT, Arc::new(|_, right| Ok(right))); - for op in vec!["+=", "-=", "*=", "/=", "%="] { + // Iterate over an array literal `[...]` instead of `vec![...]` to avoid heap allocations + for op in ["+=", "-=", "*=", "/=", "%="] { self.register( op, 20, @@ -88,7 +89,7 @@ impl InfixOpManager { ); } - for op in vec!["<<=", ">>=", "&=", "^=", "|="] { + for op in ["<<=", ">>=", "&=", "^=", "|="] { self.register( op, 20, @@ -109,7 +110,7 @@ impl InfixOpManager { ); } - for (op, precedence) in vec![("||", 40), ("&&", 50)] { + for (op, precedence) in [("||", 40), ("&&", 50)] { self.register( op, precedence, @@ -127,7 +128,7 @@ impl InfixOpManager { ); } - for op in vec!["<", "<=", ">", ">="] { + for op in ["<", "<=", ">", ">="] { self.register( op, 60, @@ -148,7 +149,7 @@ impl InfixOpManager { ); } - for op in vec!["==", "!="] { + for op in ["==", "!="] { self.register( op, 60, @@ -166,7 +167,7 @@ impl InfixOpManager { ); } - for (op, precedence) in vec![("|", 70), ("^", 80), ("&", 90), ("<<", 100), (">>", 100)] { + for (op, precedence) in [("|", 70), ("^", 80), ("&", 90), ("<<", 100), (">>", 100)] { self.register( op, precedence, @@ -187,7 +188,7 @@ impl InfixOpManager { ); } - for (op, precedence) in vec![("+", 110), ("-", 110), ("*", 120), ("/", 120), ("%", 120)] { + for (op, precedence) in [("+", 110), ("-", 110), ("*", 120), ("/", 120), ("%", 120)] { self.register( op, precedence, diff --git a/src/parser.rs b/src/parser.rs index aab9cc0..155d116 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -52,22 +52,16 @@ impl<'a> fmt::Display for ExprAST<'a> { Self::Unary(op, rhs) => { write!(f, "Unary AST: Op: {}, Rhs: {}", op, rhs) } - Self::Binary(op, lhs, rhs) => write!( - f, - "Binary AST: Op: {}, Lhs: {}, Rhs: {}", - op, - lhs, - rhs - ), + Self::Binary(op, lhs, rhs) => { + write!(f, "Binary AST: Op: {}, Lhs: {}, Rhs: {}", op, lhs, rhs) + } Self::Postfix(lhs, op) => { write!(f, "Postfix AST: Lhs: {}, Op: {}", lhs, op,) } Self::Ternary(condition, lhs, rhs) => write!( f, "Ternary AST: Condition: {}, Lhs: {}, Rhs: {}", - condition, - lhs, - rhs + condition, lhs, rhs ), Self::Reference(name) => write!(f, "Reference AST: reference: {}", name), Self::Function(name, params) => {