Skip to content

Commit bf0e27c

Browse files
committed
0.9.1 barely any difference in benchmarks, removed depth tracking for
allocation sizes
1 parent 82422a8 commit bf0e27c

File tree

1 file changed

+31
-48
lines changed

1 file changed

+31
-48
lines changed

src/parser.rs

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// This makes for some ugly code, but it is faster. Hopefully in the future
1818
// with MIR support the compiler will get smarter about this.
1919

20-
use std::{ str, slice, char, f64 };
20+
use std::{ ptr, mem, str, slice, char, f64 };
2121
use object::Object;
2222
use { JsonValue, Error, Result };
2323

@@ -53,18 +53,6 @@ struct Parser<'a> {
5353

5454
// Lenght of the source
5555
length: usize,
56-
57-
// Current depth. Objects and arrays increment depth when they
58-
// start being parsed, decrement when they stop being parsed.
59-
depth: usize,
60-
61-
// Size stack is an auxiliary array holding expected heap allocation
62-
// sizes on each level of depth, up to 16. When an array of objects,
63-
// the size stack will be set to the length of the first object parsed,
64-
// so that each consecutive object can do a guess for a precise heap
65-
// allocation for it's entires, reducing the amount of reallocations
66-
// for large files conisderably!
67-
size_stack: [usize; 16],
6856
}
6957

7058

@@ -423,8 +411,6 @@ impl<'a> Parser<'a> {
423411
byte_ptr: source.as_ptr(),
424412
index: 0,
425413
length: source.len(),
426-
depth: 0,
427-
size_stack: [3; 16],
428414
}
429415
}
430416

@@ -721,22 +707,6 @@ impl<'a> Parser<'a> {
721707
Ok(num * exponent_to_power(e * sign))
722708
}
723709

724-
#[inline(always)]
725-
fn set_alloc_size(&mut self, size: usize) {
726-
if self.depth < 16 {
727-
self.size_stack[self.depth] = size;
728-
}
729-
}
730-
731-
#[inline(always)]
732-
fn get_alloc_size(&mut self) -> usize {
733-
if self.depth < 16 {
734-
self.size_stack[self.depth]
735-
} else {
736-
3
737-
}
738-
}
739-
740710
// Given how compilcated reading numbers and strings is, reading objects
741711
// is actually pretty simple.
742712
fn read_object(&mut self) -> Result<Object> {
@@ -745,9 +715,7 @@ impl<'a> Parser<'a> {
745715
b'\"' => expect_string!(self)
746716
};
747717

748-
let mut object = Object::with_capacity(self.get_alloc_size());
749-
750-
self.depth += 1;
718+
let mut object = Object::with_capacity(3);
751719

752720
expect!(self, b':');
753721

@@ -767,36 +735,51 @@ impl<'a> Parser<'a> {
767735
object.insert(key, expect_value!(self));
768736
}
769737

770-
self.depth -= 1;
771-
772-
self.set_alloc_size(object.len());
773-
774738
Ok(object)
775739
}
776740

777741
// And reading arrays is simpler still!
778742
fn read_array(&mut self) -> Result<Vec<JsonValue>> {
779743
let first = expect_value!{ self, b']' => return Ok(Vec::new()) };
780744

781-
let mut array = Vec::with_capacity(self.get_alloc_size());
745+
let mut array = Vec::with_capacity(2);
782746

783-
self.depth += 1;
747+
unsafe {
748+
// First member can be written to the array without any checks!
749+
ptr::copy_nonoverlapping(
750+
&first as *const JsonValue,
751+
array.as_mut_ptr(),
752+
1
753+
);
754+
mem::forget(first);
755+
array.set_len(1);
756+
}
784757

785-
array.push(first);
758+
expect!{
759+
self,
760+
b']' => return Ok(array),
761+
b',' => {
762+
// Same for the second one!
763+
let value = expect_value!(self);
764+
unsafe {
765+
ptr::copy_nonoverlapping(
766+
&value as *const JsonValue,
767+
array.as_mut_ptr().offset(1),
768+
1
769+
);
770+
mem::forget(value);
771+
array.set_len(2);
772+
}
773+
}
774+
}
786775

787776
loop {
788777
expect!{ self,
789778
b']' => break,
790-
b',' => {
791-
array.push(expect_value!(self));
792-
}
779+
b',' => array.push(expect_value!(self))
793780
};
794781
}
795782

796-
self.depth -= 1;
797-
798-
self.set_alloc_size(array.len());
799-
800783
Ok(array)
801784
}
802785

0 commit comments

Comments
 (0)