icingaweb2/library/vendor/Zend/Stdlib/SplPriorityQueue.php

500 lines
13 KiB
PHP

<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Stdlib
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
/**
* SplPriorityQueue
*
* PHP 5.2.X userland implementation of PHP's SplPriorityQueue
*/
class SplPriorityQueue implements Iterator , Countable
{
/**
* Extract data only
*/
const EXTR_DATA = 0x00000001;
/**
* Extract priority only
*/
const EXTR_PRIORITY = 0x00000002;
/**
* Extract an array of ('data' => $value, 'priority' => $priority)
*/
const EXTR_BOTH = 0x00000003;
/**
* Count of items in the queue
* @var int
*/
protected $count = 0;
/**
* Flag indicating what should be returned when iterating or extracting
* @var int
*/
protected $extractFlags = self::EXTR_DATA;
/**
* @var bool|array
*/
protected $preparedQueue = false;
/**
* All items in the queue
* @var array
*/
protected $queue = array();
/**
* Constructor
*
* Creates a new, empty queue
*
* @return void
*/
public function __construct()
{
}
/**
* Compare two priorities
*
* Returns positive integer if $priority1 is greater than $priority2, 0
* if equal, negative otherwise.
*
* Unused internally, and only included in order to retain the same
* interface as PHP's SplPriorityQueue.
*
* @param mixed $priority1
* @param mixed $priority2
* @return int
*/
public function compare($priority1, $priority2)
{
if ($priority1 > $priority2) {
return 1;
}
if ($priority1 == $priority2) {
return 0;
}
return -1;
}
/**
* Countable: return number of items composed in the queue
*
* @return int
*/
public function count()
{
return $this->count;
}
/**
* Iterator: return current item
*
* @return mixed
*/
public function current()
{
if (!$this->preparedQueue) {
$this->rewind();
}
if (!$this->count) {
throw new OutOfBoundsException('Cannot iterate SplPriorityQueue; no elements present');
}
if (!is_array($this->preparedQueue)) {
throw new DomainException(sprintf(
"Queue was prepared, but is empty?\n PreparedQueue: %s\n Internal Queue: %s\n",
var_export($this->preparedQueue, 1),
var_export($this->queue, 1)
));
}
$return = array_shift($this->preparedQueue);
$priority = $return['priority'];
$priorityKey = $return['priorityKey'];
$key = $return['key'];
unset($return['key']);
unset($return['priorityKey']);
unset($this->queue[$priorityKey][$key]);
switch ($this->extractFlags) {
case self::EXTR_DATA:
return $return['data'];
case self::EXTR_PRIORITY:
return $return['priority'];
case self::EXTR_BOTH:
default:
return $return;
};
}
/**
* Extract a node from top of the heap and sift up
*
* Returns either the value, the priority, or both, depending on the extract flag.
*
* @return mixed;
*/
public function extract()
{
if (!$this->count) {
return null;
}
if (!$this->preparedQueue) {
$this->prepareQueue();
}
if (empty($this->preparedQueue)) {
return null;
}
$return = array_shift($this->preparedQueue);
$priority = $return['priority'];
$priorityKey = $return['priorityKey'];
$key = $return['key'];
unset($return['key']);
unset($return['priorityKey']);
unset($this->queue[$priorityKey][$key]);
$this->count--;
switch ($this->extractFlags) {
case self::EXTR_DATA:
return $return['data'];
case self::EXTR_PRIORITY:
return $return['priority'];
case self::EXTR_BOTH:
default:
return $return;
};
}
/**
* Insert a value into the heap, at the specified priority
*
* @param mixed $value
* @param mixed $priority
* @return void
*/
public function insert($value, $priority)
{
if (!is_scalar($priority)) {
$priority = serialize($priority);
}
if (!isset($this->queue[$priority])) {
$this->queue[$priority] = array();
}
$this->queue[$priority][] = $value;
$this->count++;
$this->preparedQueue = false;
}
/**
* Is the queue currently empty?
*
* @return bool
*/
public function isEmpty()
{
return (0 == $this->count);
}
/**
* Iterator: return current key
*
* @return mixed Usually an int or string
*/
public function key()
{
return $this->count;
}
/**
* Iterator: Move pointer forward
*
* @return void
*/
public function next()
{
$this->count--;
}
/**
* Recover from corrupted state and allow further actions on the queue
*
* Unimplemented, and only included in order to retain the same interface as PHP's
* SplPriorityQueue.
*
* @return void
*/
public function recoverFromCorruption()
{
}
/**
* Iterator: Move pointer to first item
*
* @return void
*/
public function rewind()
{
if (!$this->preparedQueue) {
$this->prepareQueue();
}
}
/**
* Set the extract flags
*
* Defines what is extracted by SplPriorityQueue::current(),
* SplPriorityQueue::top() and SplPriorityQueue::extract().
*
* - SplPriorityQueue::EXTR_DATA (0x00000001): Extract the data
* - SplPriorityQueue::EXTR_PRIORITY (0x00000002): Extract the priority
* - SplPriorityQueue::EXTR_BOTH (0x00000003): Extract an array containing both
*
* The default mode is SplPriorityQueue::EXTR_DATA.
*
* @param int $flags
* @return void
*/
public function setExtractFlags($flags)
{
$expected = array(
self::EXTR_DATA => true,
self::EXTR_PRIORITY => true,
self::EXTR_BOTH => true,
);
if (!isset($expected[$flags])) {
throw new InvalidArgumentException(sprintf('Expected an EXTR_* flag; received %s', $flags));
}
$this->extractFlags = $flags;
}
/**
* Return the value or priority (or both) of the top node, depending on
* the extract flag
*
* @return mixed
*/
public function top()
{
$this->sort();
$keys = array_keys($this->queue);
$key = array_shift($keys);
if (preg_match('/^(a|O):/', $key)) {
$key = unserialize($key);
}
if ($this->extractFlags == self::EXTR_PRIORITY) {
return $key;
}
if ($this->extractFlags == self::EXTR_DATA) {
return $this->queue[$key][0];
}
return array(
'data' => $this->queue[$key][0],
'priority' => $key,
);
}
/**
* Iterator: is the current position valid for the queue
*
* @return bool
*/
public function valid()
{
return (bool) $this->count;
}
/**
* Sort the queue
*
* @return void
*/
protected function sort()
{
krsort($this->queue);
}
/**
* Prepare the queue for iteration and/or extraction
*
* @return void
*/
protected function prepareQueue()
{
$this->sort();
$count = $this->count;
$queue = array();
foreach ($this->queue as $priority => $values) {
$priorityKey = $priority;
if (preg_match('/^(a|O):/', $priority)) {
$priority = unserialize($priority);
}
foreach ($values as $key => $value) {
$queue[$count] = array(
'data' => $value,
'priority' => $priority,
'priorityKey' => $priorityKey,
'key' => $key,
);
$count--;
}
}
$this->preparedQueue = $queue;
}
}
}
/**
* Serializable version of SplPriorityQueue
*
* Also, provides predictable heap order for datums added with the same priority
* (i.e., they will be emitted in the same order they are enqueued).
*
* @category Zend
* @package Zend_Stdlib
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Stdlib_SplPriorityQueue extends SplPriorityQueue implements Serializable
{
/**
* @var int Seed used to ensure queue order for items of the same priority
*/
protected $serial = PHP_INT_MAX;
/**
* @var bool
*/
protected $isPhp53;
/**
* Constructor
*
* @return void
*/
public function __construct()
{
$this->isPhp53 = version_compare(PHP_VERSION, '5.3', '>=');
}
/**
* Insert a value with a given priority
*
* Utilizes {@var $serial} to ensure that values of equal priority are
* emitted in the same order in which they are inserted.
*
* @param mixed $datum
* @param mixed $priority
* @return void
*/
public function insert($datum, $priority)
{
// If using the native PHP SplPriorityQueue implementation, we need to
// hack around it to ensure that items registered at the same priority
// return in the order registered. In the userland version, this is not
// necessary.
if ($this->isPhp53) {
if (!is_array($priority)) {
$priority = array($priority, $this->serial--);
}
}
parent::insert($datum, $priority);
}
/**
* Serialize to an array
*
* Array will be priority => data pairs
*
* @return array
*/
public function toArray()
{
$this->setExtractFlags(self::EXTR_BOTH);
$array = array();
while ($this->valid()) {
$array[] = $this->current();
$this->next();
}
$this->setExtractFlags(self::EXTR_DATA);
// Iterating through a priority queue removes items
foreach ($array as $item) {
$this->insert($item['data'], $item['priority']);
}
// Return only the data
$return = array();
foreach ($array as $item) {
$return[] = $item['data'];
}
return $return;
}
/**
* Serialize
*
* @return string
*/
public function serialize()
{
$data = array();
$this->setExtractFlags(self::EXTR_BOTH);
while ($this->valid()) {
$data[] = $this->current();
$this->next();
}
$this->setExtractFlags(self::EXTR_DATA);
// Iterating through a priority queue removes items
foreach ($data as $item) {
$this->insert($item['data'], $item['priority']);
}
return serialize($data);
}
/**
* Deserialize
*
* @param string $data
* @return void
*/
public function unserialize($data)
{
foreach (unserialize($data) as $item) {
$this->insert($item['data'], $item['priority']);
}
}
}