Unroll switch range case if range has only one number.

This commit is contained in:
Stephen Chung 2021-12-22 10:48:19 +08:00
parent 7ff50451cc
commit 1c50efbac8
2 changed files with 47 additions and 21 deletions

View File

@ -144,10 +144,17 @@ impl fmt::Debug for StmtBlock {
} }
} }
impl From<StmtBlock> for Stmt { impl From<Stmt> for StmtBlock {
#[inline(always)] #[inline]
fn from(block: StmtBlock) -> Self { fn from(stmt: Stmt) -> Self {
Self::Block(block.0.into_boxed_slice(), block.1) match stmt {
Stmt::Block(mut block, pos) => Self(block.iter_mut().map(mem::take).collect(), pos),
Stmt::Noop(pos) => Self(StaticVec::new_const(), pos),
_ => {
let pos = stmt.position();
Self(vec![stmt].into(), pos)
}
}
} }
} }
@ -176,7 +183,13 @@ pub enum Stmt {
Noop(Position), Noop(Position),
/// `if` expr `{` stmt `}` `else` `{` stmt `}` /// `if` expr `{` stmt `}` `else` `{` stmt `}`
If(Expr, Box<(StmtBlock, StmtBlock)>, Position), If(Expr, Box<(StmtBlock, StmtBlock)>, Position),
/// `switch` expr `if` condition `{` literal or _ `=>` stmt `,` ... `}` /// `switch` expr `{` literal or range or _ `if` condition `=>` stmt `,` ... `}`
///
/// ### Data Structure
///
/// 0) Hash table for (condition, block)
/// 1) Default block
/// 2) List of ranges: (start, end, inclusive, condition, statement)
Switch( Switch(
Expr, Expr,
Box<( Box<(
@ -262,17 +275,10 @@ impl Default for Stmt {
} }
} }
impl From<Stmt> for StmtBlock { impl From<StmtBlock> for Stmt {
#[inline] #[inline(always)]
fn from(stmt: Stmt) -> Self { fn from(block: StmtBlock) -> Self {
match stmt { Self::Block(block.0.into_boxed_slice(), block.1)
Stmt::Block(mut block, pos) => Self(block.iter_mut().map(mem::take).collect(), pos),
Stmt::Noop(pos) => Self(StaticVec::new_const(), pos),
_ => {
let pos = stmt.position();
Self(vec![stmt].into(), pos)
}
}
} }
} }

View File

@ -15,7 +15,7 @@ use crate::tokenizer::{
}; };
use crate::types::dynamic::AccessMode; use crate::types::dynamic::AccessMode;
use crate::{ use crate::{
calc_fn_hash, calc_qualified_fn_hash, calc_qualified_var_hash, Engine, ExclusiveRange, calc_fn_hash, calc_qualified_fn_hash, calc_qualified_var_hash, Dynamic, Engine, ExclusiveRange,
Identifier, ImmutableString, InclusiveRange, LexError, ParseError, ParseErrorType, Position, Identifier, ImmutableString, InclusiveRange, LexError, ParseError, ParseErrorType, Position,
Scope, Shared, StaticVec, AST, INT, Scope, Shared, StaticVec, AST, INT,
}; };
@ -1095,7 +1095,29 @@ fn parse_switch(
def_stmt = match (hash, range) { def_stmt = match (hash, range) {
(None, Some(range)) => { (None, Some(range)) => {
ranges.push((range.0, range.1, range.2, condition, stmt.into())); let is_empty = if range.2 {
(range.0..=range.1).is_empty()
} else {
(range.0..range.1).is_empty()
};
if !is_empty {
match (range.1.checked_sub(range.0), range.2) {
// Unroll single range
(Some(1), false) | (Some(0), true) => {
let value = Dynamic::from_int(range.0);
let hasher = &mut get_hasher();
value.hash(hasher);
let hash = hasher.finish();
if !table.contains_key(&hash) {
table.insert(hash, (condition.clone(), stmt.into()).into());
}
}
// Other range
_ => ranges.push((range.0, range.1, range.2, condition, stmt.into())),
}
}
None None
} }
(Some(hash), None) => { (Some(hash), None) => {
@ -1103,9 +1125,7 @@ fn parse_switch(
None None
} }
(None, None) => Some(stmt.into()), (None, None) => Some(stmt.into()),
(Some(_), Some(_)) => { _ => unreachable!("both hash and range in `switch` statement case"),
unreachable!("cannot have both a hash and a range in a `switch` statement")
}
}; };
match input.peek().expect(NEVER_ENDS) { match input.peek().expect(NEVER_ENDS) {