TinyButStrong - the PHP Template Engine
Categories > TBS next version >

f_Loc_PrmRead optimization

The forum is closed. Please use Stack Overflow for submitting new questions. Use tags: tinybutstrong , opentbs

By: Sheepy
Date: 2013-12-03
Time: 05:15

f_Loc_PrmRead optimization

Hi. I am tracking the performance of my current project, and realise that f_Loc_PrmRead is spending the most time of all TBS functions.
(Of all functions in my current project, actually.)

So I tried to optimise it, mainly by refactoring condition checks.  The main loop is still recognizable.

In dynamic columns example and display columns example, I get 5-10% speed up to whole program.

static function f_Loc_PrmRead(&$Txt,$Pos,$XmlTag,$DelimChrs,$BegStr,$EndStr,&$Loc,&$PosEnd,$WithPos=false) {

    $BegLen = strlen($BegStr);
    $BegChr = $BegStr[0];
    $BegIs1 = ($BegLen===1);

    $DelimIdx = false;
    $DelimCnt = 0;
    $DelimChr = '';
    $BegCnt = 0;
    $SubName = $Loc->SubOk;

    $Status = 0; // 0: name not started, 1: name started, 2: name ended, 3: equal found, 4: value started
    $PosName = 0;
    $PosNend = 0;
    $PosVal = 0;

    // Variables for checking the loop
    $PosEnd = strpos($Txt,$EndStr,$Pos);
    if ($PosEnd===false) return;

    while (true) {

        $Chr = $Txt[$Pos];

        if ($DelimIdx) { // Reading in the string

            $b4PosEnd = $PosEnd - 1; // Skip to next delimiter or end of position
            while ( $Chr !== $DelimChr && $Pos < $b4PosEnd ) {
                $Pos++;
                $Chr = $Txt[$Pos];
            }

            if ($Chr===$DelimChr) { // Quote found
                if ($Chr===$Txt[$Pos+1]) { // Double Quote => the string continue with un-double the quote
                    $Pos++;
                } else { // Simple Quote => end of string
                    $DelimIdx = false;
                }
            }

        } elseif ($BegCnt===0) { // Reading outside the string

            // Analyzing parameters
            if (($Chr===' ') || ($Chr==="\r") || ($Chr==="\n")) {

                if ($Status===1) {
                    if ($SubName && ($XmlTag===false)) {
                        // Accept spaces in TBS subname.
                    } else {
                        $Status = 2;
                        $PosNend = $Pos;
                    }
                } elseif ($XmlTag && ($Status===4)) {
                    self::f_Loc_PrmCompute($Txt,$Loc,$SubName,$Status,$XmlTag,$DelimChr,$DelimCnt,$PosName,$PosNend,$PosVal,$Pos,$WithPos);
                    $Status = 0;
                }

            } elseif (($Chr===';') && ($XmlTag===false)) {

                self::f_Loc_PrmCompute($Txt,$Loc,$SubName,$Status,$XmlTag,$DelimChr,$DelimCnt,$PosName,$PosNend,$PosVal,$Pos,$WithPos);
                $Status = 0;

            } elseif (($Chr==='=') && ($Status===2||$Status===1)) {

                if ($Status===1) {
                    $PosNend = $Pos;
                }
                $Status = 3;

            } else {

                switch ($Status) {
                case 1:
                case 4:
                    break;
                case 2:
                case 3:
                    if ($XmlTag && $Status === 2) {
                        self::f_Loc_PrmCompute($Txt,$Loc,$SubName,$Status,$XmlTag,$DelimChr,$DelimCnt,$PosName,$PosNend,$PosVal,$Pos,$WithPos);
                        $Status = 1;
                        $PosName = $Pos;
                    } else {
                        $Status = 4;
                        $DelimCnt = 0;
                        $PosVal = $Pos;
                    }
                    break;
                default:
                    $Status = 1;
                    $PosName = $Pos;
                }

                $DelimIdx = strpos($DelimChrs,$Chr);
                if ($DelimIdx===false) {
                    if ($Chr===$BegChr && ($BegIs1 || substr($Txt,$Pos,$BegLen)===$BegStr)) {
                        $BegCnt++;
                    }
                } else {
                    $DelimChr = $Chr;
                    $DelimCnt++;
                    $DelimIdx = true;
                }
            }
        } else {
            if ($Chr===$BegChr && ($BegIs1 || substr($Txt,$Pos,$BegLen)===$BegStr)) {
                $BegCnt++;
            }
        }

        // Next char
        $Pos++;

        // We check if it's the end
        if ($Pos===$PosEnd) {
            if ($XmlTag) {
                if ($Txt[$Pos-1]==='/') $Pos--; // In case last attribute is stuck to "/>"
                self::f_Loc_PrmCompute($Txt,$Loc,$SubName,$Status,$XmlTag,$DelimChr,$DelimCnt,$PosName,$PosNend,$PosVal,$Pos,$WithPos);
                break;
            } elseif ($DelimIdx===false) {
                if ($BegCnt>0) {
                    $BegCnt--;
                } else {
                    self::f_Loc_PrmCompute($Txt,$Loc,$SubName,$Status,$XmlTag,$DelimChr,$DelimCnt,$PosName,$PosNend,$PosVal,$Pos,$WithPos);
                    break;
                }
            }
            $PosEnd = strpos($Txt,$EndStr,$PosEnd+1);
            if ($PosEnd===false) return;
        }

    }

    $PosEnd = $PosEnd + (strlen($EndStr)-1);

}

Speed up not as much as I hoped, but still.

Should be possible to gain more speed with a rewrite, but would also be more risk and time...
By: Skrol29
Date: 2013-12-06
Time: 01:17

Re: f_Loc_PrmRead optimization

Thanks for your submitting, I'm studying it...