Skip to content

Commit

Permalink
fix(perf): Don't clone globals
Browse files Browse the repository at this point in the history
Part of #95

Before
test bench_parse_template  ... bench:      27,407 ns/iter (+/- 11,395)
test bench_parse_text      ... bench:         638 ns/iter (+/- 46)
test bench_parse_variable  ... bench:       2,479 ns/iter (+/- 212)
test bench_render_template ... bench:       8,046 ns/iter (+/- 2,514)
test bench_render_text     ... bench:         344 ns/iter (+/- 23)
test bench_render_variable ... bench:       1,578 ns/iter (+/- 243)

After
test bench_parse_template  ... bench:      26,348 ns/iter (+/- 4,703)
test bench_parse_text      ... bench:         653 ns/iter (+/- 169)
test bench_parse_variable  ... bench:       2,647 ns/iter (+/- 187)
test bench_render_template ... bench:       6,898 ns/iter (+/- 1,526)
test bench_render_text     ... bench:         276 ns/iter (+/- 28)
test bench_render_variable ... bench:         418 ns/iter (+/- 29)

BREAKING CHANGE: `Context` now works with a `&dyn Globals` instead of an
`Object`.
  • Loading branch information
epage committed Sep 18, 2018
1 parent 430d439 commit fbc1c15
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 24 deletions.
66 changes: 44 additions & 22 deletions src/interpreter/context.rs
Expand Up @@ -7,6 +7,7 @@ use value::{Index, Object, Value};

use super::Argument;
use super::{BoxedValueFilter, FilterValue};
use super::Globals;

pub fn unexpected_value_error<S: ToString>(expected: &str, actual: Option<S>) -> Error {
let actual = actual.map(|x| x.to_string());
Expand Down Expand Up @@ -68,11 +69,14 @@ impl CycleStateInner {
}

/// See `cycle` tag.
pub struct CycleState<'a> {
context: &'a mut Context,
pub struct CycleState<'a, 'g>
where
'g: 'a
{
context: &'a mut Context<'g>,
}

impl<'a> CycleState<'a> {
impl<'a, 'g> CycleState<'a, 'g> {
pub fn cycle_element(&mut self, name: &str, values: &[Argument]) -> Result<Value> {
let index = self.context.cycles.cycle_index(name, values.len());
if index >= values.len() {
Expand All @@ -87,22 +91,27 @@ impl<'a> CycleState<'a> {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Stack {
globals: Object,
lazy_static! {
static ref EMPTY_GLOBALS: Object = Object::new();
}

#[derive(Debug, Clone)]
pub struct Stack<'g> {
globals: &'g Globals,
stack: Vec<Object>,
}

impl Stack {
impl<'g> Stack<'g> {
pub fn empty() -> Self {
let empty: &Object = &*EMPTY_GLOBALS;
Self {
globals: Object::new(),
globals: empty,
// Mutable frame for globals.
stack: vec![Object::new()],
}
}

pub fn with_globals(globals: Object) -> Self {
pub fn with_globals(globals: &'g Globals) -> Self {
let mut stack = Self::empty();
stack.globals = globals;
stack
Expand Down Expand Up @@ -198,25 +207,28 @@ impl Stack {
}
}

impl Default for Stack {
impl<'g> Default for Stack<'g> {
fn default() -> Self {
Self::empty()
}
}

#[derive(Default)]
pub struct ContextBuilder {
globals: Object,
pub struct ContextBuilder<'g> {
globals: &'g Globals,
filters: sync::Arc<HashMap<&'static str, BoxedValueFilter>>,
}

impl ContextBuilder {
impl<'g> ContextBuilder<'g> {
/// Creates a new, empty rendering context.
pub fn new() -> Self {
Default::default()
let empty: &Object = &*EMPTY_GLOBALS;
Self {
globals: empty,
filters: Default::default(),
}
}

pub fn set_globals(mut self, values: Object) -> Self {
pub fn set_globals(mut self, values: &'g Globals) -> Self {
self.globals = values;
self
}
Expand All @@ -229,7 +241,7 @@ impl ContextBuilder {
self
}

pub fn build(self) -> Context {
pub fn build(self) -> Context<'g> {
Context {
stack: Stack::with_globals(self.globals),
interrupt: InterruptState::default(),
Expand All @@ -239,17 +251,23 @@ impl ContextBuilder {
}
}

impl<'g> Default for ContextBuilder<'g> {
fn default() -> Self {
Self::new()
}
}

#[derive(Default)]
pub struct Context {
stack: Stack,
pub struct Context<'g> {
stack: Stack<'g>,

interrupt: InterruptState,
cycles: CycleStateInner,

filters: sync::Arc<HashMap<&'static str, BoxedValueFilter>>,
}

impl Context {
impl<'g> Context<'g> {
pub fn new() -> Self {
Context::default()
}
Expand All @@ -269,15 +287,19 @@ impl Context {
&mut self.interrupt
}

pub fn cycles(&mut self) -> CycleState {
pub fn cycles<'a>(&'a mut self) -> CycleState<'a, 'g>
where 'g: 'a
{
CycleState { context: self }
}

pub fn stack(&self) -> &Stack {
&self.stack
}

pub fn stack_mut(&mut self) -> &mut Stack {
pub fn stack_mut<'a>(&'a mut self) -> &'a mut Stack<'g>
where 'g: 'a
{
&mut self.stack
}

Expand Down
14 changes: 14 additions & 0 deletions src/interpreter/globals.rs
@@ -0,0 +1,14 @@
use std::fmt;

use value::Object;
use value::Value;

pub trait Globals: fmt::Debug {
fn get<'a>(&'a self, name: &str) -> Option<&'a Value>;
}

impl Globals for Object {
fn get<'a>(&'a self, name: &str) -> Option<&'a Value> {
self.get(name)
}
}
2 changes: 2 additions & 0 deletions src/interpreter/mod.rs
@@ -1,6 +1,7 @@
mod argument;
mod context;
mod filter;
mod globals;
mod output;
mod renderable;
mod template;
Expand All @@ -12,6 +13,7 @@ pub use self::context::{
unexpected_value_error, Context, ContextBuilder, Interrupt, InterruptState,
};
pub use self::filter::{BoxedValueFilter, FilterError, FilterResult, FilterValue, FnFilterValue};
pub use self::globals::Globals;
pub use self::output::{FilterPrototype, Output};
pub use self::renderable::Renderable;
pub use self::template::Template;
Expand Down
5 changes: 3 additions & 2 deletions src/template.rs
Expand Up @@ -7,6 +7,7 @@ use error::Result;

use interpreter;
use interpreter::Renderable;
use interpreter::Globals;

pub struct Template {
pub(crate) template: interpreter::Template,
Expand All @@ -22,10 +23,10 @@ impl Template {
}

/// Renders an instance of the Template, using the given globals.
pub fn render_to(&self, writer: &mut Write, globals: &Object) -> Result<()> {
pub fn render_to(&self, writer: &mut Write, globals: &Globals) -> Result<()> {
let mut data = interpreter::ContextBuilder::new()
.set_filters(&self.filters)
.set_globals(globals.clone())
.set_globals(globals)
.build();
self.template.render_to(writer, &mut data)
}
Expand Down

0 comments on commit fbc1c15

Please sign in to comment.