Textpattern CMS support forum

You are not logged in. Register | Login | Help

#31 2014-12-08 14:14:15

etc
Developer
Registered: 2010-11-11
Posts: 3,159
Website

Re: Making plugins first-class citizens

What makes me hesitate too, is that putting

if(strpos($thing, '<txp:') === false) return $thing;

at the very beginning of parse() (and the like), divides the runtime by 5 if $thing does not contain <txp:tags />. This optimization would not be possible with “short” tags.


etc_[ query | search | pagination | date | tree | cache ]

Offline

#32 2014-12-08 16:35:35

colak
Admin
From: Cyprus
Registered: 2004-11-20
Posts: 7,246
Website

Re: Making plugins first-class citizens

I’ve been following this thread since the beginning. Although I can understand the idea of fewer keystrokes I am wondering if this is just aimed for programmers who have to type all the time. In my view – although this would be a good update it would also mean that many plugins will just stop working (correct me if I am wrong).

Wouldn’t it be more productive for now to focus on real updates of the txp system such as extending the custom fields?


Yiannis
——————————
neme.org | hblack.net | LABS | State Machines | Respbublika! | NeMe @ github

Online

#33 2014-12-08 16:53:36

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 8,629
Website

Re: Making plugins first-class citizens

colak wrote #286329:

it would also mean that many plugins will just stop working (correct me if I am wrong).

It will have no impact on the behaviour of existing plugins, aside from turbo-charging them with their very own else tag. This enables site admins to match up a plugin’s container with a plugin-prefixed else tag, which improves template readability. Aside from that, yes, less typing if you wish to take advantage of it, otherwise it’s business as usual.

The new syntax would merely be offered as an option for those that prefer it.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Offline

#34 2014-12-08 18:53:59

ruud
Developer emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: Making plugins first-class citizens

etc wrote #286328:

What makes me hesitate too, is that putting

if(strpos($thing, '<txp:') === false) return $thing;...

at the very beginning of parse() (and the like), divides the runtime by 5 if $thing does not contain <txp:tags />. This optimization would not be possible with “short” tags.

Using this, has the same effect in most cases:

if(strpos($thing, ':') === false) return $thing;

Offline

#35 2014-12-08 19:11:32

etc
Developer
Registered: 2010-11-11
Posts: 3,159
Website

Re: Making plugins first-class citizens

Bloke wrote #286330:

turbo-charging them with their very own else tag.

only if the plugin is already <txp:else />-aware, right?

ruud wrote #286334:

Using this, has the same effect in most cases: if(strpos($thing, ':') === false) return $thing;...

Not if $thing contains http:, for example, which is rather common.


etc_[ query | search | pagination | date | tree | cache ]

Offline

#36 2014-12-08 21:33:31

ruud
Developer emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: Making plugins first-class citizens

etc wrote #286335:

only if the plugin is already <txp:else />-aware, right?

Yes.

Not if $thing contains http:, for example, which is rather common.

It’s not that common in the simple if/else constructs that this optimisation targets. I’ve checked two websites (one of them being TXP.org). I could find only one case where the : optimisation would fail. In around 95% of situations where the optimisation should save time it works just fine.

Offline

#37 2014-12-09 09:02:08

etc
Developer
Registered: 2010-11-11
Posts: 3,159
Website

Re: Making plugins first-class citizens

ruud wrote #286340:

It’s not that common in the simple if/else constructs that this optimisation targets.

Ruud, I really appreciate your argumentation, and you are certainly right re EvalElse() statistics. But look, I write about parse() optimization too. About 95% of article bodies contain "link":http://... (transformed into <a href="http://..."> by Textile), or some <image src="http://..." />, and no <txp:tag />. For these, optimizing parse() would make <txp:body /> processing much faster.


etc_[ query | search | pagination | date | tree | cache ]

Offline

#38 2014-12-09 20:01:31

ruud
Developer emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: Making plugins first-class citizens

You’re right. Patching a patch:

- static $prefix = null;
+ static $istag, $prefix = null,  

  if ($prefix === null) {
-   $prefix = get_pref('allow_short_tags', '1') ? '[a-z]{3}' : 'txp';
+   if (get_pref('allow_short_tags', '1')) {
+     $prefix = '[a-z]{3}';
+     $istag = ':';
+   } else {
+     $prefix = 'txp';
+     $istag = '<txp:';
+   }
  }
+
+ if (strpos($thing, $istag) === false) return $thing;

Adding a parse attribute <txp:body parse="0" /> is another way to solve this, although you lose part of the speed increase by having to parse the attribute ;)

Offline

#39 2014-12-10 11:59:52

etc
Developer
Registered: 2010-11-11
Posts: 3,159
Website

Re: Making plugins first-class citizens

Great! I would only make short tags opt-in, since it’s a new feature: if (get_pref('allow_short_tags', '0')) ...

ruud wrote #286383:

Adding a parse attribute <txp:body parse="0" /> is another way to solve this, although you lose part of the speed increase by having to parse the attribute ;)

No, we don’t want to lose a dime. Let’s win even more: why re-parse what is already parsed? When you process, say

<txp:article limit="9999">
	<txp:title />
</txp:article>

you call preg_split(... '<txp:title />' ...) 9999 times. Why not to do it once, and cache the result? How could this $thing inside <txp:article /> change anyway?

My current parse() running here looks like this (sorry for flooding):

function parse($thing='') {

	static $stack = array();
	if(strpos($thing, '<txp:') === false) return $thing;

//	don't parse $thing twice!!!

	$hash = sha1($thing);
	if(isset($stack[$hash])) $tags = $stack[$hash];
	else
	{
		$tags = array();
		$level  = 0;
		$inside = '';
		$istag  = FALSE;

		$f = '@(</?txp:\w+(?:\s+\w+\s*=\s*(?:"(?:[^"]|"")*"|\'(?:[^\']|\'\')*\'|[^\s\'"/>]+))*\s*/?'.chr(62).')@s';
		$t = '@:(\w+)(.*?)/?.$@s';

		$parsed = preg_split($f, $thing, -1, PREG_SPLIT_DELIM_CAPTURE);

		foreach ($parsed as $chunk)
		{
			if ($istag)
			{
				if ($level === 0)
				{
					preg_match($t, $chunk, $tag);

					if (substr($chunk, -2, 1) === '/')
						$tags[] = array('tag' => $tag[1], 'atts' => $tag[2], 'thing' => null);
					else
					{ # opening
						$level++;
					}
				}
				else
				{
					if (substr($chunk, 1, 1) === '/')
					{ # closing
						if (--$level === 0)
						{
							$tags[] = array('tag' => $tag[1], 'atts' => $tag[2], 'thing' => $inside);
							$inside = '';
						}
						else
						{
							$inside .= $chunk;
						}
					}
					elseif (substr($chunk, -2, 1) !== '/')
					{ # opening inside open
						++$level;
						$inside .= $chunk;
					}
					else
					{
						$inside .= $chunk;
					}
				}
			}
			else
			{
				if ($level) $inside .= $chunk;
				else $tags[] = $chunk;
			}
			$istag = !$istag;
		}
		$stack[$hash] = $tags;
	}

	$out = '';
	foreach($tags as $i => $tag) $out .= $i&1 ? processTags($tag['tag'], $tag['atts'], $tag['thing']) : $tag;

	return $out;
}

Same idea for EvalElse() and splat(). There is a risk of SHA1 collision, but none (unlike MD5) is known for the moment. The speedup on long loop structures is measurable, though preg_split() is not the slowest part of it. No particular memory consumption detected atm.

What you devs think of it?


etc_[ query | search | pagination | date | tree | cache ]

Offline

#40 2014-12-10 20:41:01

ruud
Developer emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: Making plugins first-class citizens

Some benchmarks, each row with a different $thing string:

$thing = 'some very long text that does not contain an else tag';
$thing = '<txp:tag />';
$thing = '<txp:tag><txp:tag><txp:tag><txp:tag><txp:tag></txp:tag></txp:tag></txp:tag></txp:tag></txp:tag>';
$thing = '<txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag /><txp:tag />';

	0.6327	0.5520	0.6313	0.9997	1.1809
	2.2664	1.3447	1.6456	2.8423	3.8831
	5.2651	0.9088	1.4774	3.7682	6.3109
	16.1752	8.4240	9.6645	14.2784	25.8554

column1: current parser (250.000 times)
column2: etc parser (250.000 loop)
column3: etc parser (10 loop, 25.000 times)
column4: etc parser (2 loop, 125.000 times)
column5: etc parser (no loop, 250.000 times)

I should add that I removed the first optimisation from the etc parser to be able to test just the effect of sha1 hashing.

Summarised. You gain quite a bit in loops, but you also lose a lot in non looping series of tags.

Offline

Board footer

Powered by FluxBB