-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnaive_slice.rs
209 lines (193 loc) · 6.9 KB
/
naive_slice.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//! Like [crate::naive], but uses &str instead of String
use std::{
cmp::Ordering,
iter::Peekable,
mem::{align_of, forget, size_of},
str::CharIndices,
};
use crate::shared::{
day13_framework,
res_pool::{self, Alloc},
};
/// Creates and drops Vecs each line.
pub mod no_pool {
use super::{day13_generalized, res_pool::GlobalHeapProxy};
pub fn day13(input: &str) -> usize {
let list_pool = &mut GlobalHeapProxy {};
day13_generalized(input, list_pool)
}
}
/// Uses an object pool for the Vecs.
pub mod pooled {
use super::{day13_generalized, res_pool::ResPool};
pub fn day13(input: &str) -> usize {
let new_list = &mut Vec::new;
let list_pool = &mut ResPool::new(new_list);
day13_generalized(input, list_pool)
}
}
fn day13_generalized<'a>(input: &str, list_pool: &mut impl Alloc<Vec<Element<'a>>>) -> usize {
day13_framework(input, |left, right| {
let left = Element::parse(left, list_pool);
let right = Element::parse(right, list_pool);
let cmp = left.cmp(&right);
left.scavenge(list_pool);
right.scavenge(list_pool);
cmp
})
}
#[derive(PartialEq, Eq, Debug)]
enum Element<'a> {
Num(&'a str),
List(Vec<Element<'a>>),
}
impl<'a> PartialOrd for Element<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> Ord for Element<'a> {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Element::Num(s), Element::Num(o)) => s.cmp(o),
(Element::Num(_), Element::List(o)) => {
if o.is_empty() {
return Ordering::Greater;
}
let first_elem_cmp = self.cmp(&o[0]);
if first_elem_cmp.is_eq() && o.len() > 1 {
Ordering::Less
} else {
first_elem_cmp
}
}
(Element::List(_), Element::Num(_)) => other.cmp(self).reverse(),
(Element::List(s), Element::List(o)) => s.cmp(o),
}
}
}
impl<'a> Element<'a> {
fn parse<'pool>(s: &'a str, list_pool: &mut impl Alloc<Vec<Element<'pool>>>) -> Element<'a> {
let s = s.trim();
if s.chars().all(|ch| ch.is_ascii_digit()) {
return Self::Num(s);
}
fn parse_number<'a>(chars: &mut Peekable<CharIndices>, source: &'a str) -> &'a str {
let start = chars.next().unwrap().0;
let mut end = start;
while let Some((idx, _)) = chars.next_if(|(_, c)| c.is_ascii_digit()) {
end = idx;
}
source.split_at(end + 1).0.split_at(start).1
}
fn consume_until_closing_bracket<'b, 'source>(
chars: &mut Peekable<CharIndices>,
source: &'source str,
list_pool: &mut impl Alloc<Vec<Element<'b>>>,
) -> Vec<Element<'source>> {
let mut vec = launder(list_pool.withdraw());
loop {
match chars
.peek()
.expect("expected a closing brace, but reached end of input")
.1
{
']' => {
chars.next();
return vec;
}
'0'..='9' => {
vec.push(Element::Num(parse_number(chars, source)));
}
'[' => {
let _ = chars.next();
vec.push(Element::List(consume_until_closing_bracket(
chars, source, list_pool,
)));
}
',' => panic!("expected element before comma"),
' ' => continue,
char => panic!("invalid character `{char}`"),
}
loop {
match chars
.peek()
.expect("expected a closing brace or comma after element")
.1
{
' ' => continue,
',' => {
chars.next();
break;
}
']' => break,
char => panic!("invalid character `{char}`"),
}
}
}
}
let mut chars = s.char_indices().peekable();
match chars.peek().expect("empty line!").1 {
'[' => {
let _ = chars.next();
let ele = Element::List(consume_until_closing_bracket(&mut chars, s, list_pool));
match chars.next().map(|a| a.1) {
Some(',') => {
panic!("unexpected comma (top-level needs to be a list, with '[' and ']')")
}
Some(']') => {
panic!("unexpected ']' (duplicate closing ']', or missing opening '['?")
}
Some(ch) => {
panic!("unexpected character after complete number: `{ch}`");
}
_ => (),
}
ele
}
'0'..='9' => {
let ele = Element::Num(parse_number(&mut chars, s));
match chars.next().map(|a| a.1) {
Some(',') => {
panic!("unexpected comma (top-level needs to be a list, with '[' and ']')")
}
Some(']') => panic!("unexpected ']' (did you forget the opening '['?"),
Some(ch) => {
panic!("unexpected character after complete number: `{ch}`");
}
_ => (),
}
ele
}
' ' => unreachable!(),
ch => panic!("invalid character `{ch}`"),
}
}
/// tears down this object and returns resources (Vecs, Strings) to the given pools)
fn scavenge<'b>(self, list_pool: &mut impl Alloc<Vec<Element<'b>>>) {
match self {
Self::List(mut items) => {
for ele in items.drain(..) {
ele.scavenge(list_pool);
}
let items = launder(items);
list_pool.deposit(items);
}
Element::Num(_) => {}
}
}
}
/// Intended use: ignore lifetime of Vec<Element<'a>> when vec is empty before *and* after
/// borrowing
fn launder<Old, New>(mut old: Vec<Old>) -> Vec<New> {
assert!(old.is_empty());
assert_eq!(align_of::<Old>(), align_of::<New>());
assert_eq!(size_of::<Old>(), size_of::<New>());
unsafe {
let capacity = old.capacity();
let len = old.len();
let ptr = old.as_mut_ptr();
forget(old);
Vec::from_raw_parts(ptr as *mut New, len, capacity)
}
}