Skip to content

Commit 290eecc

Browse files
committed
Optimize NfaTrans
1 parent bcb61a4 commit 290eecc

File tree

1 file changed

+63
-88
lines changed

1 file changed

+63
-88
lines changed

src/day19.rs

Lines changed: 63 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,39 @@ fn to_idx(i: u8) -> usize {
2626
}
2727
}
2828

29+
const HAS_START: u16 = 1 << 15;
2930
#[derive(Debug, Copy, Clone)]
30-
enum NfaTrans {
31-
None,
32-
Start,
33-
Next(usize),
34-
Both(usize),
35-
}
31+
struct NfaTrans(u16);
3632

3733
impl NfaTrans {
34+
#[inline(always)]
35+
const fn empty() -> Self {
36+
NfaTrans(0)
37+
}
38+
39+
#[inline(always)]
40+
fn has_start(&self) -> bool {
41+
self.0 & HAS_START != 0
42+
}
43+
44+
#[inline(always)]
45+
fn get_next(&self) -> u16 {
46+
self.0 & (!HAS_START)
47+
}
48+
49+
#[inline(always)]
3850
fn add_start(&mut self) {
39-
match *self {
40-
NfaTrans::None => *self = NfaTrans::Start,
41-
NfaTrans::Next(n) => *self = NfaTrans::Both(n),
42-
_ => {}
43-
}
51+
self.0 |= HAS_START;
4452
}
4553

46-
fn add_or_foolow(&mut self, new_nfa_node: impl FnOnce() -> usize) -> usize {
47-
match *self {
48-
NfaTrans::None => {
49-
let new = new_nfa_node();
50-
*self = NfaTrans::Next(new);
51-
new
52-
}
53-
NfaTrans::Start => {
54-
let new = new_nfa_node();
55-
*self = NfaTrans::Both(new);
56-
new
57-
}
58-
NfaTrans::Next(n) => n,
59-
NfaTrans::Both(n) => n,
54+
#[inline(always)]
55+
fn add_or_foolow(&mut self, new_nfa_node: impl FnOnce() -> u16) -> u16 {
56+
if self.get_next() == 0 {
57+
let new = new_nfa_node();
58+
self.0 |= new;
59+
new
60+
} else {
61+
self.get_next()
6062
}
6163
}
6264
}
@@ -74,7 +76,7 @@ pub fn part1(s: &str) -> u64 {
7476
// #[target_feature(enable = "avx2,bmi1,bmi2,cmpxchg16b,lzcnt,movbe,popcnt")]
7577
fn inner_part1(s: &[u8]) -> u64 {
7678
let mut nfa = heapless::Vec::<[NfaTrans; 5], NFA_SIZE>::new();
77-
nfa.push([NfaTrans::None; 5]).unwrap();
79+
nfa.push([NfaTrans::empty(); 5]).unwrap();
7880

7981
let mut i = 0;
8082
let mut nfa_node = 0;
@@ -93,21 +95,21 @@ fn inner_part1(s: &[u8]) -> u64 {
9395
} else {
9496
let mut nfa_trans = nfa[nfa_node][color];
9597
let next_nfa_node = nfa_trans.add_or_foolow(|| {
96-
let new_nfa_node = nfa.len();
97-
nfa.push([NfaTrans::None; 5]).unwrap();
98+
let new_nfa_node = nfa.len() as u16;
99+
nfa.push([NfaTrans::empty(); 5]).unwrap();
98100
new_nfa_node
99101
});
100102
nfa[nfa_node][color] = nfa_trans;
101103

102-
nfa_node = next_nfa_node;
104+
nfa_node = next_nfa_node as usize;
103105
i += 1;
104106
}
105107
}
106108

107109
let mut sum = 0;
108110

109-
let mut states1 = &mut (true, heapless::Vec::<usize, NFA_SIZE>::new());
110-
let mut states2 = &mut (false, heapless::Vec::<usize, NFA_SIZE>::new());
111+
let mut states1 = &mut (true, heapless::Vec::<u16, NFA_SIZE>::new());
112+
let mut states2 = &mut (false, heapless::Vec::<u16, NFA_SIZE>::new());
111113

112114
while i < s.len() {
113115
if s[i] == b'\n' {
@@ -126,34 +128,18 @@ fn inner_part1(s: &[u8]) -> u64 {
126128

127129
if states1.0 {
128130
let next = nfa[0][color];
129-
match next {
130-
NfaTrans::None => {}
131-
NfaTrans::Start => {
132-
states2.0 = true;
133-
}
134-
NfaTrans::Next(n) => {
135-
states2.1.push(n).unwrap();
136-
}
137-
NfaTrans::Both(n) => {
138-
states2.0 = true;
139-
states2.1.push(n).unwrap();
140-
}
131+
132+
states2.0 |= next.has_start();
133+
if next.get_next() != 0 {
134+
states2.1.push(next.get_next()).unwrap();
141135
}
142136
}
143137
for s in states1.1.iter() {
144-
let next = nfa[*s][color];
145-
match next {
146-
NfaTrans::None => {}
147-
NfaTrans::Start => {
148-
states2.0 = true;
149-
}
150-
NfaTrans::Next(n) => {
151-
states2.1.push(n).unwrap();
152-
}
153-
NfaTrans::Both(n) => {
154-
states2.0 = true;
155-
states2.1.push(n).unwrap();
156-
}
138+
let next = nfa[*s as usize][color];
139+
140+
states2.0 |= next.has_start();
141+
if next.get_next() != 0 {
142+
states2.1.push(next.get_next()).unwrap();
157143
}
158144
}
159145
std::mem::swap(&mut states2, &mut states1);
@@ -180,7 +166,7 @@ pub fn part2(s: &str) -> u64 {
180166
// #[target_feature(enable = "avx2,bmi1,bmi2,cmpxchg16b,lzcnt,movbe,popcnt")]
181167
fn inner_part2(s: &[u8]) -> u64 {
182168
let mut nfa = heapless::Vec::<[NfaTrans; 5], NFA_SIZE>::new();
183-
nfa.push([NfaTrans::None; 5]).unwrap();
169+
nfa.push([NfaTrans::empty(); 5]).unwrap();
184170

185171
let mut i = 0;
186172
let mut nfa_node = 0;
@@ -199,25 +185,26 @@ fn inner_part2(s: &[u8]) -> u64 {
199185
} else {
200186
let mut nfa_trans = nfa[nfa_node][color];
201187
let next_nfa_node = nfa_trans.add_or_foolow(|| {
202-
let new_nfa_node = nfa.len();
203-
nfa.push([NfaTrans::None; 5]).unwrap();
188+
let new_nfa_node = nfa.len() as u16;
189+
nfa.push([NfaTrans::empty(); 5]).unwrap();
204190
new_nfa_node
205191
});
206192
nfa[nfa_node][color] = nfa_trans;
207193

208-
nfa_node = next_nfa_node;
194+
nfa_node = next_nfa_node as usize;
209195
i += 1;
210196
}
211197
}
212198

213199
let mut sum = 0;
214200

215-
let mut states1 = &mut (1, heapless::Vec::<(usize, u64), NFA_SIZE>::new());
216-
let mut states2 = &mut (0, heapless::Vec::<(usize, u64), NFA_SIZE>::new());
201+
let mut states1 = &mut (1u64, heapless::Vec::<(u16, u64), NFA_SIZE>::new());
202+
let mut states2 = &mut (0u64, heapless::Vec::<(u16, u64), NFA_SIZE>::new());
217203

218204
while i < s.len() {
219205
if s[i] == b'\n' {
220206
sum += states1.0;
207+
221208
states1.1.clear();
222209
states1.0 = 1;
223210
i += 1;
@@ -230,38 +217,26 @@ fn inner_part2(s: &[u8]) -> u64 {
230217

231218
if states1.0 > 0 {
232219
let next = nfa[0][color];
233-
match next {
234-
NfaTrans::None => {}
235-
NfaTrans::Start => {
236-
states2.0 += states1.0;
237-
}
238-
NfaTrans::Next(n) => {
239-
states2.1.push((n, states1.0)).unwrap();
240-
}
241-
NfaTrans::Both(n) => {
242-
states2.0 += states1.0;
243-
states2.1.push((n, states1.0)).unwrap();
244-
}
220+
221+
if next.has_start() {
222+
states2.0 += states1.0;
223+
}
224+
if next.get_next() != 0 {
225+
states2.1.push((next.get_next(), states1.0)).unwrap();
245226
}
246227
}
247228
for (s, amount) in states1.1.iter() {
248-
let next = nfa[*s][color];
249-
match next {
250-
NfaTrans::None => {}
251-
NfaTrans::Start => {
252-
states2.0 += *amount;
253-
}
254-
NfaTrans::Next(n) => {
255-
states2.1.push((n, *amount)).unwrap();
256-
}
257-
NfaTrans::Both(n) => {
258-
states2.0 += *amount;
259-
states2.1.push((n, *amount)).unwrap();
260-
}
229+
let next = nfa[*s as usize][color];
230+
231+
if next.has_start() {
232+
states2.0 += amount;
233+
}
234+
if next.get_next() != 0 {
235+
states2.1.push((next.get_next(), *amount)).unwrap();
261236
}
262237
}
263-
264238
std::mem::swap(&mut states2, &mut states1);
239+
265240
if states1.0 == 0 && states1.1.is_empty() {
266241
while i < s.len() && s[i] != b'\n' {
267242
i += 1;

0 commit comments

Comments
 (0)