wikimedia/mediawiki-extensions-CirrusSearch

View on GitHub
includes/Parser/QueryStringRegex/OffsetTracker.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace CirrusSearch\Parser\QueryStringRegex;

use Wikimedia\Assert\Assert;

/**
 * Simple class to track offsets
 * Supports only simple cases (no support for overlapping offsets)
 */
class OffsetTracker {

    /**
     * Always ordered with no overlapping offsets
     * @var int[] array of end offsets indexed by start offsets
     */
    private $offsets = [];

    /**
     * @param int $start start offset (inclusive)
     * @param int $end end offset (exclusive)
     */
    public function append( $start, $end ) {
        Assert::precondition( $start < $end, '$start < $end' );
        $this->offsets[$start] = $end;
        ksort( $this->offsets );
    }

    /**
     * Append an array of ParsedNode into the tracker.
     * The array must not contain any overlapping node.
     * @param \CirrusSearch\Parser\AST\ParsedNode[] $nodes
     */
    public function appendNodes( array $nodes ) {
        foreach ( $nodes as $node ) {
            // slow: Assert::invariant( $this->overlap( $node->getStartOffset(), $node->getEndOffset() ) );
            $this->offsets[$node->getStartOffset()] = $node->getEndOffset();
        }
        ksort( $this->offsets );
    }

    /**
     * @param int $start
     * @param int $end
     * @return bool
     */
    public function overlap( $start, $end ) {
        Assert::precondition( $start < $end, '$start < $end' );
        foreach ( $this->offsets as $s => $e ) {
            if ( $e > $start && $s < $end ) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return int[]
     */
    public function getOffsets() {
        return $this->offsets;
    }

    /**
     * return this first unconsumed offset in this tracker
     * greater than $offset
     * @param int $offset
     * @return int
     */
    public function getMinimalUnconsumedOffset( $offset = 0 ) {
        Assert::precondition( $offset >= 0, '$offset >= 0' );
        foreach ( $this->offsets as $start => $end ) {
            if ( $offset < $start ) {
                return $offset;
            }
            $offset = $end > $offset ? $end : $offset;
        }
        return $offset;
    }
}