Version 1
[yaffs-website] / vendor / zendframework / zend-stdlib / src / FastPriorityQueue.php
diff --git a/vendor/zendframework/zend-stdlib/src/FastPriorityQueue.php b/vendor/zendframework/zend-stdlib/src/FastPriorityQueue.php
new file mode 100644 (file)
index 0000000..16d2bcc
--- /dev/null
@@ -0,0 +1,343 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link      http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Iterator;
+use Countable;
+use Serializable;
+use SplPriorityQueue as PhpSplPriorityQueue;
+
+/**
+ * This is an efficient implementation of an integer priority queue in PHP
+ *
+ * This class acts like a queue with insert() and extract(), removing the
+ * elements from the queue and it also acts like an Iterator without removing
+ * the elements. This behaviour can be used in mixed scenarios with high
+ * performance boost.
+ */
+class FastPriorityQueue implements Iterator, Countable, Serializable
+{
+    const EXTR_DATA     = PhpSplPriorityQueue::EXTR_DATA;
+    const EXTR_PRIORITY = PhpSplPriorityQueue::EXTR_PRIORITY;
+    const EXTR_BOTH     = PhpSplPriorityQueue::EXTR_BOTH;
+
+    /**
+     * @var integer
+     */
+    protected $extractFlag = self::EXTR_DATA;
+
+    /**
+     * Elements of the queue, divided by priorities
+     *
+     * @var array
+     */
+    protected $values = [];
+
+    /**
+     * Array of priorities
+     *
+     * @var array
+     */
+    protected $priorities = [];
+
+    /**
+     * Array of priorities used for the iteration
+     *
+     * @var array
+     */
+    protected $subPriorities = [];
+
+    /**
+     * Max priority
+     *
+     * @var integer
+     */
+    protected $maxPriority = 0;
+
+    /**
+     * Total number of elements in the queue
+     *
+     * @var integer
+     */
+    protected $count = 0;
+
+    /**
+     * Index of the current element in the queue
+     *
+     * @var integer
+     */
+    protected $index = 0;
+
+    /**
+     * Sub index of the current element in the same priority level
+     *
+     * @var integer
+     */
+    protected $subIndex = 0;
+
+    /**
+     * Insert an element in the queue with a specified priority
+     *
+     * @param mixed $value
+     * @param integer $priority a positive integer
+     */
+    public function insert($value, $priority)
+    {
+        if (! is_int($priority)) {
+            throw new Exception\InvalidArgumentException('The priority must be an integer');
+        }
+        $this->values[$priority][] = $value;
+        if (! isset($this->priorities[$priority])) {
+            $this->priorities[$priority] = $priority;
+            $this->maxPriority           = max($priority, $this->maxPriority);
+        }
+        ++$this->count;
+    }
+
+    /**
+     * Extract an element in the queue according to the priority and the
+     * order of insertion
+     *
+     * @return mixed
+     */
+    public function extract()
+    {
+        if (! $this->valid()) {
+            return false;
+        }
+        $value = $this->current();
+        $this->nextAndRemove();
+        return $value;
+    }
+
+    /**
+     * Remove an item from the queue
+     *
+     * This is different than {@link extract()}; its purpose is to dequeue an
+     * item.
+     *
+     * Note: this removes the first item matching the provided item found. If
+     * the same item has been added multiple times, it will not remove other
+     * instances.
+     *
+     * @param  mixed $datum
+     * @return bool False if the item was not found, true otherwise.
+     */
+    public function remove($datum)
+    {
+        $this->rewind();
+        while ($this->valid()) {
+            if (current($this->values[$this->maxPriority]) === $datum) {
+                $index = key($this->values[$this->maxPriority]);
+                unset($this->values[$this->maxPriority][$index]);
+                --$this->count;
+                return true;
+            }
+            $this->next();
+        }
+        return false;
+    }
+
+    /**
+     * Get the total number of elements in the queue
+     *
+     * @return integer
+     */
+    public function count()
+    {
+        return $this->count;
+    }
+
+    /**
+     * Get the current element in the queue
+     *
+     * @return mixed
+     */
+    public function current()
+    {
+        switch ($this->extractFlag) {
+            case self::EXTR_DATA:
+                return current($this->values[$this->maxPriority]);
+            case self::EXTR_PRIORITY:
+                return $this->maxPriority;
+            case self::EXTR_BOTH:
+                return [
+                    'data'     => current($this->values[$this->maxPriority]),
+                    'priority' => $this->maxPriority
+                ];
+        }
+    }
+
+    /**
+     * Get the index of the current element in the queue
+     *
+     * @return integer
+     */
+    public function key()
+    {
+        return $this->index;
+    }
+
+    /**
+     * Set the iterator pointer to the next element in the queue
+     * removing the previous element
+     */
+    protected function nextAndRemove()
+    {
+        if (false === next($this->values[$this->maxPriority])) {
+            unset($this->priorities[$this->maxPriority]);
+            unset($this->values[$this->maxPriority]);
+            $this->maxPriority = empty($this->priorities) ? 0 : max($this->priorities);
+            $this->subIndex    = -1;
+        }
+        ++$this->index;
+        ++$this->subIndex;
+        --$this->count;
+    }
+
+    /**
+     * Set the iterator pointer to the next element in the queue
+     * without removing the previous element
+     */
+    public function next()
+    {
+        if (false === next($this->values[$this->maxPriority])) {
+            unset($this->subPriorities[$this->maxPriority]);
+            reset($this->values[$this->maxPriority]);
+            $this->maxPriority = empty($this->subPriorities) ? 0 : max($this->subPriorities);
+            $this->subIndex    = -1;
+        }
+        ++$this->index;
+        ++$this->subIndex;
+    }
+
+    /**
+     * Check if the current iterator is valid
+     *
+     * @return boolean
+     */
+    public function valid()
+    {
+        return isset($this->values[$this->maxPriority]);
+    }
+
+    /**
+     * Rewind the current iterator
+     */
+    public function rewind()
+    {
+        $this->subPriorities = $this->priorities;
+        $this->maxPriority   = empty($this->priorities) ? 0 : max($this->priorities);
+        $this->index         = 0;
+        $this->subIndex      = 0;
+    }
+
+    /**
+     * Serialize to an array
+     *
+     * Array will be priority => data pairs
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        $array = [];
+        foreach (clone $this as $item) {
+            $array[] = $item;
+        }
+        return $array;
+    }
+
+    /**
+     * Serialize
+     *
+     * @return string
+     */
+    public function serialize()
+    {
+        $clone = clone $this;
+        $clone->setExtractFlags(self::EXTR_BOTH);
+
+        $data = [];
+        foreach ($clone as $item) {
+            $data[] = $item;
+        }
+
+        return serialize($data);
+    }
+
+    /**
+     * Deserialize
+     *
+     * @param  string $data
+     * @return void
+     */
+    public function unserialize($data)
+    {
+        foreach (unserialize($data) as $item) {
+            $this->insert($item['data'], $item['priority']);
+        }
+    }
+
+    /**
+     * Set the extract flag
+     *
+     * @param integer $flag
+     */
+    public function setExtractFlags($flag)
+    {
+        switch ($flag) {
+            case self::EXTR_DATA:
+            case self::EXTR_PRIORITY:
+            case self::EXTR_BOTH:
+                $this->extractFlag = $flag;
+                break;
+            default:
+                throw new Exception\InvalidArgumentException("The extract flag specified is not valid");
+        }
+    }
+
+    /**
+     * Check if the queue is empty
+     *
+     * @return boolean
+     */
+    public function isEmpty()
+    {
+        return empty($this->values);
+    }
+
+    /**
+     * Does the queue contain the given datum?
+     *
+     * @param  mixed $datum
+     * @return bool
+     */
+    public function contains($datum)
+    {
+        foreach ($this->values as $values) {
+            if (in_array($datum, $values)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Does the queue have an item with the given priority?
+     *
+     * @param  int $priority
+     * @return bool
+     */
+    public function hasPriority($priority)
+    {
+        return isset($this->values[$priority]);
+    }
+}