Oops, forgot to change this in r71426
[lhc/web/wiklou.git] / includes / StringUtils.php
index 95c755d..82b9dc1 100644 (file)
@@ -36,7 +36,11 @@ class StringUtils {
         * This implementation is slower than hungryDelimiterReplace but uses far less
         * memory. The delimiters are literal strings, not regular expressions.
         *
-        * @param string $flags Regular expression flags
+        * @param $startDelim String: start delimiter
+        * @param $endDelim String: end delimiter
+        * @param $callback Callback: function to call on each match
+        * @param $subject String
+        * @param $flags String: regular expression flags
         */
        # If the start delimiter ends with an initial substring of the end delimiter,
        # e.g. in the case of C-style comments, the behaviour differs from the model
@@ -111,17 +115,17 @@ class StringUtils {
                return $output;
        }
 
-       /*
+       /**
         * Perform an operation equivalent to
         *
         *   preg_replace( "!$startDelim(.*)$endDelim!$flags", $replace, $subject )
         *
-        * @param string $startDelim Start delimiter regular expression
-        * @param string $endDelim End delimiter regular expression
-        * @param string $replace Replacement string. May contain $1, which will be
-        *               replaced by the text between the delimiters
-        * @param string $subject String to search
-        * @return string The string with the matches replaced
+        * @param $startDelim String: start delimiter regular expression
+        * @param $endDelim String: end delimiter regular expression
+        * @param $replace String: replacement string. May contain $1, which will be
+        *                 replaced by the text between the delimiters
+        * @param $subject String to search
+        * @return String: The string with the matches replaced
         */
        static function delimiterReplace( $startDelim, $endDelim, $replace, $subject, $flags = '' ) {
                $replacer = new RegexlikeReplacer( $replace );
@@ -132,8 +136,8 @@ class StringUtils {
        /**
         * More or less "markup-safe" explode()
         * Ignores any instances of the separator inside <...>
-        * @param string $separator
-        * @param string $text
+        * @param $separator String
+        * @param $text String
         * @return array
         */
        static function explodeMarkup( $separator, $text ) {
@@ -159,14 +163,26 @@ class StringUtils {
         * Escape a string to make it suitable for inclusion in a preg_replace()
         * replacement parameter.
         *
-        * @param string $string
-        * @return string
+        * @param $string String
+        * @return String
         */
        static function escapeRegexReplacement( $string ) {
                $string = str_replace( '\\', '\\\\', $string );
                $string = str_replace( '$', '\\$', $string );
                return $string;
        }
+
+       /**
+        * Workalike for explode() with limited memory usage.
+        * Returns an Iterator
+        */
+       static function explode( $separator, $subject ) {
+               if ( substr_count( $subject, $separator ) > 1000 ) {
+                       return new ExplodeIterator( $separator, $subject );
+               } else {
+                       return new ArrayIterator( explode( $separator, $subject ) );
+               }
+       }
 }
 
 /**
@@ -283,6 +299,17 @@ class ReplacementArray {
                $this->fss = false;
        }
 
+       function removePair( $from ) {
+               unset($this->data[$from]);
+               $this->fss = false;
+       }
+
+       function removeArray( $data ) {
+               foreach( $data as $from => $to )
+                       $this->removePair( $from );
+               $this->fss = false;
+       }
+
        function replace( $subject ) {
                if ( function_exists( 'fss_prep_replace' ) ) {
                        wfProfileIn( __METHOD__.'-fss' );
@@ -299,3 +326,90 @@ class ReplacementArray {
                return $result;
        }
 }
+
+/**
+ * An iterator which works exactly like:
+ * 
+ * foreach ( explode( $delim, $s ) as $element ) {
+ *    ...
+ * }
+ *
+ * Except it doesn't use 193 byte per element
+ */
+class ExplodeIterator implements Iterator {
+       // The subject string
+       var $subject, $subjectLength;
+
+       // The delimiter
+       var $delim, $delimLength;
+
+       // The position of the start of the line
+       var $curPos;
+
+       // The position after the end of the next delimiter
+       var $endPos;
+
+       // The current token
+       var $current;
+
+       /** 
+        * Construct a DelimIterator
+        */
+       function __construct( $delim, $s ) {
+               $this->subject = $s;
+               $this->delim = $delim;
+
+               // Micro-optimisation (theoretical)
+               $this->subjectLength = strlen( $s );
+               $this->delimLength = strlen( $delim );
+
+               $this->rewind();
+       }
+
+       function rewind() {
+               $this->curPos = 0;
+               $this->endPos = strpos( $this->subject, $this->delim );
+               $this->refreshCurrent();
+       }
+
+
+       function refreshCurrent() {
+               if ( $this->curPos === false ) {
+                       $this->current = false;
+               } elseif ( $this->curPos >= $this->subjectLength ) {
+                       $this->current = '';
+               } elseif ( $this->endPos === false ) {
+                       $this->current = substr( $this->subject, $this->curPos );
+               } else {
+                       $this->current = substr( $this->subject, $this->curPos, $this->endPos - $this->curPos );
+               }
+       }
+
+       function current() {
+               return $this->current;
+       }
+
+       function key() {
+               return $this->curPos;
+       }
+
+       function next() {
+               if ( $this->endPos === false ) {
+                       $this->curPos = false;
+               } else {
+                       $this->curPos = $this->endPos + $this->delimLength;
+                       if ( $this->curPos >= $this->subjectLength ) {
+                               $this->endPos = false;
+                       } else {
+                               $this->endPos = strpos( $this->subject, $this->delim, $this->curPos );
+                       }
+               }
+               $this->refreshCurrent();
+               return $this->current;
+       }
+
+       function valid() {
+               return $this->curPos !== false;
+       }
+}
+