From 9cfb40b0fadfc00cf0517b20b0291b296e2a1d33 Mon Sep 17 00:00:00 2001 From: fabien Date: Sat, 7 Nov 2009 19:48:10 +0000 Subject: [PATCH] made a huge optimization for loops (up to 50% faster now) git-svn-id: http://svn.twig-project.org/trunk@117 93ef8e89-cb99-4229-a87c-7fa0fa45744b --- lib/Twig/Node/For.php | 9 +++-- lib/Twig/runtime_for.php | 81 +++++++-------------------------------------- 2 files changed, 19 insertions(+), 71 deletions(-) diff --git a/lib/Twig/Node/For.php b/lib/Twig/Node/For.php index e6d8482..184e470 100644 --- a/lib/Twig/Node/For.php +++ b/lib/Twig/Node/For.php @@ -58,10 +58,13 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface $compiler->write("\$context['_iterated'] = false;\n"); } + $var = rand(1, 999999); $compiler - ->write('foreach (twig_iterate($context, ') + ->write("\$seq$var = twig_iterator_to_array(") ->subcompile($this->seq) - ->raw(") as \$iterator)\n") + ->raw(");\n") + ->write("\$context['loop']['length'] = count(\$seq$var);\n") + ->write("for (\$i$var = 0; \$i$var < \$context['loop']['length']; \$i$var++)\n") ->write("{\n") ->indent() ; @@ -71,7 +74,7 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface $compiler->write("\$context['_iterated'] = true;\n"); } - $compiler->write('twig_set_loop_context($context, $iterator, '); + $compiler->write("twig_set_loop_context(\$context, \$seq$var, \$i$var, "); if ($this->isMultitarget) { diff --git a/lib/Twig/runtime_for.php b/lib/Twig/runtime_for.php index c587873..c526153 100644 --- a/lib/Twig/runtime_for.php +++ b/lib/Twig/runtime_for.php @@ -4,103 +4,48 @@ * This file is part of Twig. * * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -class Twig_LoopContextIterator implements Iterator +function twig_iterator_to_array($seq) { - public $context; - public $seq; - public $idx; - public $length; - public $parent; - - public function __construct(&$context, $seq, $parent) - { - $this->context = $context; - $this->seq = $seq; - $this->length = count($this->seq); - $this->parent = $parent; - } - - public function rewind() - { - $this->idx = 0; - } - - public function key() - { - } - - public function valid() - { - return $this->idx < $this->length; - } - - public function next() - { - $this->idx++; - } - - public function current() - { - return $this; - } -} - -function twig_iterate(&$context, $seq) -{ - $parent = isset($context['loop']) ? $context['loop'] : null; - - // convert the sequence to an array of values - // we convert Iterators as an array - // as our iterator access the sequence as an array if (is_array($seq)) { - $array = array_values($seq); + return array_values($seq); } elseif (is_object($seq) && $seq instanceof Iterator) { - $array = iterator_to_array($seq, false); + return iterator_to_array($seq, false); } else { - $array = array(); + return array(); } - - $context['loop'] = array('parent' => $parent); - - return new Twig_LoopContextIterator($context, $array, $parent); } -function twig_set_loop_context(&$context, $iterator, $target) +function twig_set_loop_context(&$context, $seq, $idx, $target) { - $idx = $iterator->idx; - if (is_array($target)) { - foreach ($target as $key => $value) - { - $context[$value] = $iterator->seq[$idx][$key]; - } + $context[$target[0]] = $seq[$idx][0]; + $context[$target[1]] = $seq[$idx][1]; } else { - $context[$target] = $iterator->seq[$idx]; + $context[$target] = $seq[$idx]; } $context['loop'] = array( - 'parent' => $iterator->parent, - 'length' => $iterator->length, + 'parent' => $context['_parent'], + 'length' => $context['loop']['length'], 'index0' => $idx, 'index' => $idx + 1, - 'revindex0' => $iterator->length - $idx - 1, - 'revindex' => $iterator->length - $idx, + 'revindex0' => $context['loop']['length'] - $idx - 1, + 'revindex' => $context['loop']['length'] - $idx, 'first' => $idx == 0, - 'last' => $idx + 1 == $iterator->length, + 'last' => $idx + 1 == $context['loop']['length'], ); } -- 1.7.2.5