HEX
Server: Apache
System: Linux wp02.tdr-lab.com 3.10.0-1160.42.2.el7.x86_64 #1 SMP Tue Sep 7 14:49:57 UTC 2021 x86_64
User: kusanagi (1001)
PHP: 7.4.23
Disabled: NONE
Upload Files
File: //usr/share/hhvm/hack/hacklib/containers/hacklib_iterator.php
<?php

namespace HH {
  require_once(__DIR__.SEP.'hacklib_iteratorToken.php');

  /**
   * This serves as a baseclass for iterators for all the containers. It works by
   * making use of an integer index which is incremented within the range
   * 0 - containersize.
   */
  class HACKLIB_iterator implements KeyedIterator {
    // constructor params
    private $count, $token, $getKeyAndValue;
    // current state
    private $index, $keyAndValue;

    /**
     * @param count : The total size of the container.
     * @param token : This is used to make sure that the iterator stops
     *                   working once the container has been modified.
     * @param getKeyAndValue : This is a function that, given the current index,
     *                            returns the current key and value.
     */
    public function hacklib_init($count, $token, $getKeyAndValue) {
      $this->count = $count;
      $this->token = $token;
      $this->getKeyAndValue = $getKeyAndValue;
      $this->rewind();
    }

    public function rewind() {
      if ($this->token->isNotExpired()) {
        $this->index = 0;
        $this->keyAndValue = null;
      }
    }

    public function next() {
      $this->index++;
      $this->keyAndValue = null;
    }

    private function currentKeyAndValue_UNSAFE() {
      if (!$this->keyAndValue) {
        $fn = $this->getKeyAndValue;
        $this->keyAndValue = $fn($this->index);
      }
      return $this->keyAndValue;
    }

    private function validate() {
      if ($this->token->isExpired()) {
        throw new \InvalidOperationException(
          'Collection was modified during iteration');
      }
      if (!$this->valid()) {
        throw new \InvalidOperationException('Iterator is not valid');
      }
    }

    public function current() {
      $this->validate();
      return $this->currentKeyAndValue_UNSAFE()[1];
    }

    public function key() {
      $this->validate();
      return $this->currentKeyAndValue_UNSAFE()[0];
    }

    public function valid() {
      return $this->index < $this->count;
    }
  }

  /**
   * adds a few simple methods to all containers that implement
   * iterators, mainly implemented so we can consolidate all
   * the logic dealing with iterators in one place.
   */
  trait HACKLIB_iteratable {
    //this is a token passed to all iterators so it can be invalidated.
    private $iteratorToken;

    /**
     * All iterators share a token that becomes invalidated the minute the
     * container is mutated. This creates a new token incase the current
     * one does not exist.
     */
    private function getCurrentToken() {
      if (!$this->iteratorToken) {
        $this->iteratorToken = new HACKLIB_IteratorToken();
      }
      return $this->iteratorToken;
    }

    protected function hacklib_expireAllIterators() {
      if ($this->iteratorToken) {
        $this->iteratorToken->expire();
        $this->iteratorToken = null;
      }
    }

    /**
     *  return the key and value at index i for this container
     */
    protected abstract function hacklib_getKeyAndValue($i);

    /**
     *  return the size of the given container
     */
    public abstract function count();

    /**
     *  create a new iterator of the required type.
     */
    protected abstract function hacklib_createNewIterator();

    /**
     * Returns an iterator that points to the beginning of this Container.
     */
    public function getIterator() {
      $iterator = $this->hacklib_createNewIterator();
      $iterator->hacklib_init(
        $this->count(),
        $this->getCurrentToken(),
        function ($i) {
          return $this->hacklib_getKeyAndValue($i);
        }
      );
      return $iterator;
    }
  }
}