File indexing completed on 2024-05-12 06:03:07

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Stdlib
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  */
0020 
0021 // require_once 'Zend/Stdlib/SplPriorityQueue.php';
0022 
0023 /**
0024  * Re-usable, serializable priority queue implementation
0025  *
0026  * SplPriorityQueue acts as a heap; on iteration, each item is removed from the
0027  * queue. If you wish to re-use such a queue, you need to clone it first. This 
0028  * makes for some interesting issues if you wish to delete items from the queue,
0029  * or, as already stated, iterate over it multiple times.
0030  *
0031  * This class aggregates items for the queue itself, but also composes an 
0032  * "inner" iterator in the form of an SplPriorityQueue object for performing
0033  * the actual iteration.
0034  *
0035  * @category   Zend
0036  * @package    Zend_Stdlib
0037  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0038  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0039  */
0040 class Zend_Stdlib_PriorityQueue implements Countable, IteratorAggregate, Serializable
0041 {
0042     const EXTR_DATA     = 0x00000001;
0043     const EXTR_PRIORITY = 0x00000002;
0044     const EXTR_BOTH     = 0x00000003;
0045 
0046     /**
0047      * Inner queue class to use for iteration
0048      * @var string
0049      */
0050     protected $queueClass = 'Zend_Stdlib_SplPriorityQueue';
0051 
0052     /**
0053      * Actual items aggregated in the priority queue. Each item is an array
0054      * with keys "data" and "priority".
0055      * @var array
0056      */
0057     protected $items      = array();
0058 
0059     /**
0060      * Inner queue object
0061      * @var SplPriorityQueue
0062      */
0063     protected $queue;
0064 
0065     /**
0066      * Insert an item into the queue
0067      *
0068      * Priority defaults to 1 (low priority) if none provided.
0069      * 
0070      * @param  mixed $data 
0071      * @param  int $priority 
0072      * @return Zend_Stdlib_PriorityQueue
0073      */
0074     public function insert($data, $priority = 1)
0075     {
0076         $priority = (int) $priority;
0077         $this->items[] = array(
0078             'data'     => $data,
0079             'priority' => $priority,
0080         );
0081         $this->getQueue()->insert($data, $priority);
0082         return $this;
0083     }
0084 
0085     /**
0086      * Remove an item from the queue
0087      *
0088      * This is different than {@link extract()}; its purpose is to dequeue an
0089      * item.
0090      *
0091      * This operation is potentially expensive, as it requires 
0092      * re-initialization and re-population of the inner queue.
0093      * 
0094      * Note: this removes the first item matching the provided item found. If
0095      * the same item has been added multiple times, it will not remove other 
0096      * instances.
0097      *
0098      * @param  mixed $datum
0099      * @return boolean False if the item was not found, true otherwise.
0100      */
0101     public function remove($datum)
0102     {
0103         $found = false;
0104         foreach ($this->items as $key => $item) {
0105             if ($item['data'] === $datum) {
0106                 $found = true;
0107                 break;
0108             }
0109         }
0110         if ($found) {
0111             unset($this->items[$key]);
0112             $this->queue = null;
0113             $queue = $this->getQueue();
0114             foreach ($this->items as $item) {
0115                 $queue->insert($item['data'], $item['priority']);
0116             }
0117             return true;
0118         }
0119         return false;
0120     }
0121 
0122     /**
0123      * Is the queue empty?
0124      * 
0125      * @return bool
0126      */
0127     public function isEmpty()
0128     {
0129         return (0 === $this->count());
0130     }
0131 
0132     /**
0133      * How many items are in the queue?
0134      * 
0135      * @return int
0136      */
0137     public function count()
0138     {
0139         return count($this->items);
0140     }
0141 
0142     /**
0143      * Peek at the top node in the queue, based on priority.
0144      * 
0145      * @return mixed
0146      */
0147     public function top()
0148     {
0149         return $this->getIterator()->top();
0150     }
0151 
0152     /**
0153      * Extract a node from the inner queue and sift up 
0154      * 
0155      * @return mixed
0156      */
0157     public function extract()
0158     {
0159         return $this->getQueue()->extract();
0160     }
0161 
0162     /**
0163      * Retrieve the inner iterator
0164      *
0165      * SplPriorityQueue acts as a heap, which typically implies that as items
0166      * are iterated, they are also removed. This does not work for situations
0167      * where the queue may be iterated multiple times. As such, this class 
0168      * aggregates the values, and also injects an SplPriorityQueue. This method 
0169      * retrieves the inner queue object, and clones it for purposes of 
0170      * iteration.
0171      * 
0172      * @return SplPriorityQueue
0173      */
0174     public function getIterator()
0175     {
0176         $queue = $this->getQueue();
0177         return clone $queue;
0178     }
0179 
0180     /**
0181      * Serialize the data structure
0182      * 
0183      * @return string
0184      */
0185     public function serialize()
0186     {
0187         return serialize($this->items);
0188     }
0189 
0190     /**
0191      * Unserialize a string into a Zend_Stdlib_PriorityQueue object
0192      *
0193      * Serialization format is compatible with {@link Zend_Stdlib_SplPriorityQueue}
0194      * 
0195      * @param  string $data 
0196      * @return void
0197      */
0198     public function unserialize($data)
0199     {
0200         foreach (unserialize($data) as $item) {
0201             $this->insert($item['data'], $item['priority']);
0202         }
0203     }
0204 
0205     /**
0206      * Serialize to an array
0207      *
0208      * By default, returns only the item data, and in the order registered (not
0209      * sorted). You may provide one of the EXTR_* flags as an argument, allowing
0210      * the ability to return priorities or both data and priority.
0211      * 
0212      * @param  int $flag 
0213      * @return array
0214      */
0215     public function toArray($flag = self::EXTR_DATA)
0216     {
0217         switch ($flag) {
0218             case self::EXTR_BOTH:
0219                 return $this->items;
0220             case self::EXTR_PRIORITY:
0221                 return array_map(array($this, 'returnPriority'), $this->items);
0222             case self::EXTR_DATA:
0223             default:
0224                 return array_map(array($this, 'returnData'), $this->items);
0225         }
0226     }
0227 
0228     /**
0229      * Specify the internal queue class
0230      *
0231      * Please see {@link getIterator()} for details on the necessity of an
0232      * internal queue class. The class provided should extend SplPriorityQueue.
0233      * 
0234      * @param  string $class 
0235      * @return Zend_Stdlib_PriorityQueue
0236      */
0237     public function setInternalQueueClass($class)
0238     {
0239         $this->queueClass = (string) $class;
0240         return $this;
0241     }
0242 
0243     /**
0244      * Does the queue contain the given datum?
0245      * 
0246      * @param  mixed $datum 
0247      * @return bool
0248      */
0249     public function contains($datum)
0250     {
0251         foreach ($this->items as $item) {
0252             if ($item['data'] === $datum) {
0253                 return true;
0254             }
0255         }
0256         return false;
0257     }
0258 
0259     /**
0260      * Does the queue have an item with the given priority?
0261      * 
0262      * @param  int $priority 
0263      * @return bool
0264      */
0265     public function hasPriority($priority)
0266     {
0267         foreach ($this->items as $item) {
0268             if ($item['priority'] === $priority) {
0269                 return true;
0270             }
0271         }
0272         return false;
0273     }
0274 
0275     /**
0276      * Get the inner priority queue instance
0277      * 
0278      * @return Zend_Stdlib_SplPriorityQueue
0279      */
0280     protected function getQueue()
0281     {
0282         if (null === $this->queue) {
0283             $this->queue = new $this->queueClass();
0284             if (!$this->queue instanceof SplPriorityQueue) {
0285                 throw new DomainException(sprintf(
0286                     'Zend_Stdlib_PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"',
0287                     get_class($this->queue)
0288                 ));
0289             }
0290         }
0291         return $this->queue;
0292     }
0293 
0294     /**
0295      * Return priority from an internal item
0296      *
0297      * Used as a lambda in toArray().
0298      * 
0299      * @param  array $item 
0300      * @return mixed
0301      */
0302     public function returnPriority($item)
0303     {
0304         return $item['priority'];
0305     }
0306 
0307     /**
0308      * Return data from an internal item
0309      *
0310      * Used as a lambda in toArray().
0311      * 
0312      * @param  array $item 
0313      * @return mixed
0314      */
0315     public function returnData($item)
0316     {
0317         return $item['data'];
0318     }
0319 }