Skip to content

Commit d231e2f

Browse files
arvidnrichardkiss
authored andcommitted
separate the node list into two separate vectors, to avoid the overhead of a variant discriminator for every item
1 parent 67f3543 commit d231e2f

File tree

2 files changed

+41
-30
lines changed

2 files changed

+41
-30
lines changed

src/int_allocator.rs

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,25 @@ pub struct IntAtomBuf {
66
end: u32,
77
}
88

9-
enum NodePtr {
10-
Atom(IntAtomBuf),
11-
Pair(u32, u32),
9+
#[derive(Clone, Copy)]
10+
pub struct IntPair {
11+
first: i32,
12+
rest: i32,
1213
}
1314

1415
pub struct IntAllocator {
1516
// this is effectively a grow-only stack where atoms are allocated. Atoms
1617
// are immutable, so once they are created, they will stay around until the
1718
// program completes
1819
u8_vec: Vec<u8>,
19-
node_vec: Vec<NodePtr>,
20+
21+
// storage for all pairs (positive indices)
22+
pair_vec: Vec<IntPair>,
23+
24+
// storage for all atoms (negative indices).
25+
// node index -1 refers to index 0 in this vector, -2 refers to 1 and so
26+
// on.
27+
atom_vec: Vec<IntAtomBuf>,
2028
}
2129

2230
impl Default for IntAllocator {
@@ -29,62 +37,66 @@ impl IntAllocator {
2937
pub fn new() -> Self {
3038
let mut r = IntAllocator {
3139
u8_vec: Vec::new(),
32-
node_vec: Vec::new(),
40+
pair_vec: Vec::new(),
41+
atom_vec: Vec::new(),
3342
};
3443
r.u8_vec.reserve(1024 * 1024);
44+
r.atom_vec.reserve(256);
45+
r.pair_vec.reserve(256);
3546
r.u8_vec.push(1_u8);
3647
// Preallocated empty list
37-
r.node_vec
38-
.push(NodePtr::Atom(IntAtomBuf { start: 0, end: 0 }));
48+
r.atom_vec.push(IntAtomBuf { start: 0, end: 0 });
3949
// Preallocated 1
40-
r.node_vec
41-
.push(NodePtr::Atom(IntAtomBuf { start: 0, end: 1 }));
50+
r.atom_vec.push(IntAtomBuf { start: 0, end: 1 });
4251
r
4352
}
4453
}
4554

4655
impl Allocator for IntAllocator {
47-
type Ptr = u32;
56+
type Ptr = i32;
4857
type AtomBuf = IntAtomBuf;
4958

5059
fn new_atom(&mut self, v: &[u8]) -> Self::Ptr {
5160
let start = self.u8_vec.len() as u32;
5261
self.u8_vec.extend_from_slice(v);
5362
let end = self.u8_vec.len() as u32;
54-
let r = self.node_vec.len() as u32;
55-
self.node_vec.push(NodePtr::Atom(IntAtomBuf { start, end }));
56-
r
63+
self.atom_vec.push(IntAtomBuf { start, end });
64+
-(self.atom_vec.len() as i32)
5765
}
5866

5967
fn new_pair(&mut self, first: Self::Ptr, rest: Self::Ptr) -> Self::Ptr {
60-
let r: u32 = self.node_vec.len() as u32;
61-
self.node_vec.push(NodePtr::Pair(first, rest));
68+
let r = self.pair_vec.len() as i32;
69+
self.pair_vec.push(IntPair { first, rest });
6270
r
6371
}
6472

6573
fn atom<'a>(&'a self, node: &'a Self::Ptr) -> &'a [u8] {
66-
match self.node_vec[*node as usize] {
67-
NodePtr::Atom(IntAtomBuf { start, end }) => &self.u8_vec[start as usize..end as usize],
68-
_ => panic!("expected atom, got pair"),
74+
if *node >= 0 {
75+
panic!("expected atom, got pair");
6976
}
77+
let atom = self.atom_vec[(-*node - 1) as usize];
78+
&self.u8_vec[atom.start as usize..atom.end as usize]
7079
}
7180

7281
fn buf<'a>(&'a self, node: &'a Self::AtomBuf) -> &'a [u8] {
7382
&self.u8_vec[node.start as usize..node.end as usize]
7483
}
7584

7685
fn sexp(&self, node: &Self::Ptr) -> SExp<Self::Ptr, Self::AtomBuf> {
77-
match self.node_vec[*node as usize] {
78-
NodePtr::Atom(atombuf) => SExp::Atom(atombuf),
79-
NodePtr::Pair(left, right) => SExp::Pair(left, right),
86+
if *node >= 0 {
87+
let pair = self.pair_vec[*node as usize];
88+
SExp::Pair(pair.first, pair.rest)
89+
} else {
90+
let atom = self.atom_vec[(-*node - 1) as usize];
91+
SExp::Atom(atom)
8092
}
8193
}
8294

8395
fn null(&self) -> Self::Ptr {
84-
0
96+
-1
8597
}
8698

8799
fn one(&self) -> Self::Ptr {
88-
1
100+
-2
89101
}
90102
}

src/py/run_program.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::int_allocator::IntAllocator;
44
use crate::more_ops::op_unknown;
55
use crate::node::Node;
66
use crate::py::f_table::{make_f_lookup, FLookup};
7-
use crate::reduction::{EvalErr, Reduction};
7+
use crate::reduction::Response;
88
use crate::run_program::{run_program, OperatorHandler};
99
use crate::serialize::{node_from_bytes, node_to_bytes};
1010
use lazy_static::lazy_static;
@@ -26,8 +26,8 @@ impl OperatorHandler<IntAllocator> for OperatorHandlerWithMode {
2626
&self,
2727
allocator: &mut IntAllocator,
2828
o: <IntAllocator as Allocator>::AtomBuf,
29-
argument_list: &u32,
30-
) -> Result<Reduction<u32>, EvalErr<u32>> {
29+
argument_list: &<IntAllocator as Allocator>::Ptr,
30+
) -> Response<<IntAllocator as Allocator>::Ptr> {
3131
let op = &allocator.buf(&o);
3232
if op.len() == 1 {
3333
if let Some(f) = F_TABLE[op[0] as usize] {
@@ -58,11 +58,10 @@ pub fn serialize_and_run_program(
5858
let f: Box<dyn OperatorHandler<IntAllocator>> = Box::new(OperatorHandlerWithMode {
5959
strict: (flags & STRICT_MODE) != 0,
6060
});
61-
let program: u32 = node_from_bytes(&mut allocator, program).unwrap();
61+
let program = node_from_bytes(&mut allocator, program).unwrap();
62+
let args = node_from_bytes(&mut allocator, args).unwrap();
6263

63-
let args: u32 = node_from_bytes(&mut allocator, args).unwrap();
64-
65-
let r: Result<Reduction<u32>, EvalErr<u32>> = run_program(
64+
let r = run_program(
6665
&mut allocator,
6766
&program,
6867
&args,

0 commit comments

Comments
 (0)