PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Stdlib/SplPriorityQueue.php

https://bitbucket.org/Ebozavrik/test-application
PHP | 506 lines | 243 code | 46 blank | 217 comment | 27 complexity | 3bf58d0653ff23a644af045a1c5a8466 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Stdlib
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  21. /**
  22. * SplPriorityQueue
  23. *
  24. * PHP 5.2.X userland implementation of PHP's SplPriorityQueue
  25. */
  26. class SplPriorityQueue implements Iterator, Countable
  27. {
  28. /**
  29. * Extract data only
  30. */
  31. const EXTR_DATA = 0x00000001;
  32. /**
  33. * Extract priority only
  34. */
  35. const EXTR_PRIORITY = 0x00000002;
  36. /**
  37. * Extract an array of ('data' => $value, 'priority' => $priority)
  38. */
  39. const EXTR_BOTH = 0x00000003;
  40. /**
  41. * Count of items in the queue
  42. * @var int
  43. */
  44. protected $count = 0;
  45. /**
  46. * Flag indicating what should be returned when iterating or extracting
  47. * @var int
  48. */
  49. protected $extractFlags = self::EXTR_DATA;
  50. /**
  51. * @var bool|array
  52. */
  53. protected $preparedQueue = false;
  54. /**
  55. * All items in the queue
  56. * @var array
  57. */
  58. protected $queue = array();
  59. /**
  60. * Constructor
  61. *
  62. * Creates a new, empty queue
  63. *
  64. * @return void
  65. */
  66. public function __construct ()
  67. {
  68. }
  69. /**
  70. * Compare two priorities
  71. *
  72. * Returns positive integer if $priority1 is greater than $priority2, 0
  73. * if equal, negative otherwise.
  74. *
  75. * Unused internally, and only included in order to retain the same
  76. * interface as PHP's SplPriorityQueue.
  77. *
  78. * @param mixed $priority1
  79. * @param mixed $priority2
  80. *
  81. * @return int
  82. */
  83. public function compare ($priority1, $priority2)
  84. {
  85. if ($priority1 > $priority2) {
  86. return 1;
  87. }
  88. if ($priority1 == $priority2) {
  89. return 0;
  90. }
  91. return -1;
  92. }
  93. /**
  94. * Countable: return number of items composed in the queue
  95. *
  96. * @return int
  97. */
  98. public function count ()
  99. {
  100. return $this->count;
  101. }
  102. /**
  103. * Iterator: return current item
  104. *
  105. * @return mixed
  106. */
  107. public function current ()
  108. {
  109. if (!$this->preparedQueue) {
  110. $this->rewind();
  111. }
  112. if (!$this->count) {
  113. throw new OutOfBoundsException( 'Cannot iterate SplPriorityQueue; no elements present' );
  114. }
  115. if (!is_array($this->preparedQueue)) {
  116. throw new DomainException( sprintf(
  117. "Queue was prepared, but is empty?\n PreparedQueue: %s\n Internal Queue: %s\n",
  118. var_export($this->preparedQueue, 1),
  119. var_export($this->queue, 1)
  120. ) );
  121. }
  122. $return = array_shift($this->preparedQueue);
  123. $priority = $return['priority'];
  124. $priorityKey = $return['priorityKey'];
  125. $key = $return['key'];
  126. unset( $return['key'] );
  127. unset( $return['priorityKey'] );
  128. unset( $this->queue[$priorityKey][$key] );
  129. switch ($this->extractFlags) {
  130. case self::EXTR_DATA:
  131. return $return['data'];
  132. case self::EXTR_PRIORITY:
  133. return $return['priority'];
  134. case self::EXTR_BOTH:
  135. default:
  136. return $return;
  137. }
  138. ;
  139. }
  140. /**
  141. * Extract a node from top of the heap and sift up
  142. *
  143. * Returns either the value, the priority, or both, depending on the extract flag.
  144. *
  145. * @return mixed;
  146. */
  147. public function extract ()
  148. {
  149. if (!$this->count) {
  150. return null;
  151. }
  152. if (!$this->preparedQueue) {
  153. $this->prepareQueue();
  154. }
  155. if (empty( $this->preparedQueue )) {
  156. return null;
  157. }
  158. $return = array_shift($this->preparedQueue);
  159. $priority = $return['priority'];
  160. $priorityKey = $return['priorityKey'];
  161. $key = $return['key'];
  162. unset( $return['key'] );
  163. unset( $return['priorityKey'] );
  164. unset( $this->queue[$priorityKey][$key] );
  165. $this->count--;
  166. switch ($this->extractFlags) {
  167. case self::EXTR_DATA:
  168. return $return['data'];
  169. case self::EXTR_PRIORITY:
  170. return $return['priority'];
  171. case self::EXTR_BOTH:
  172. default:
  173. return $return;
  174. }
  175. ;
  176. }
  177. /**
  178. * Insert a value into the heap, at the specified priority
  179. *
  180. * @param mixed $value
  181. * @param mixed $priority
  182. *
  183. * @return void
  184. */
  185. public function insert ($value, $priority)
  186. {
  187. if (!is_scalar($priority)) {
  188. $priority = serialize($priority);
  189. }
  190. if (!isset( $this->queue[$priority] )) {
  191. $this->queue[$priority] = array();
  192. }
  193. $this->queue[$priority][] = $value;
  194. $this->count++;
  195. $this->preparedQueue = false;
  196. }
  197. /**
  198. * Is the queue currently empty?
  199. *
  200. * @return bool
  201. */
  202. public function isEmpty ()
  203. {
  204. return ( 0 == $this->count );
  205. }
  206. /**
  207. * Iterator: return current key
  208. *
  209. * @return mixed Usually an int or string
  210. */
  211. public function key ()
  212. {
  213. return $this->count;
  214. }
  215. /**
  216. * Iterator: Move pointer forward
  217. *
  218. * @return void
  219. */
  220. public function next ()
  221. {
  222. $this->count--;
  223. }
  224. /**
  225. * Recover from corrupted state and allow further actions on the queue
  226. *
  227. * Unimplemented, and only included in order to retain the same interface as PHP's
  228. * SplPriorityQueue.
  229. *
  230. * @return void
  231. */
  232. public function recoverFromCorruption ()
  233. {
  234. }
  235. /**
  236. * Iterator: Move pointer to first item
  237. *
  238. * @return void
  239. */
  240. public function rewind ()
  241. {
  242. if (!$this->preparedQueue) {
  243. $this->prepareQueue();
  244. }
  245. }
  246. /**
  247. * Set the extract flags
  248. *
  249. * Defines what is extracted by SplPriorityQueue::current(),
  250. * SplPriorityQueue::top() and SplPriorityQueue::extract().
  251. *
  252. * - SplPriorityQueue::EXTR_DATA (0x00000001): Extract the data
  253. * - SplPriorityQueue::EXTR_PRIORITY (0x00000002): Extract the priority
  254. * - SplPriorityQueue::EXTR_BOTH (0x00000003): Extract an array containing both
  255. *
  256. * The default mode is SplPriorityQueue::EXTR_DATA.
  257. *
  258. * @param int $flags
  259. *
  260. * @return void
  261. */
  262. public function setExtractFlags ($flags)
  263. {
  264. $expected = array(
  265. self::EXTR_DATA => true,
  266. self::EXTR_PRIORITY => true,
  267. self::EXTR_BOTH => true,
  268. );
  269. if (!isset( $expected[$flags] )) {
  270. throw new InvalidArgumentException( sprintf('Expected an EXTR_* flag; received %s', $flags) );
  271. }
  272. $this->extractFlags = $flags;
  273. }
  274. /**
  275. * Return the value or priority (or both) of the top node, depending on
  276. * the extract flag
  277. *
  278. * @return mixed
  279. */
  280. public function top ()
  281. {
  282. $this->sort();
  283. $keys = array_keys($this->queue);
  284. $key = array_shift($keys);
  285. if (preg_match('/^(a|O):/', $key)) {
  286. $key = unserialize($key);
  287. }
  288. if ($this->extractFlags == self::EXTR_PRIORITY) {
  289. return $key;
  290. }
  291. if ($this->extractFlags == self::EXTR_DATA) {
  292. return $this->queue[$key][0];
  293. }
  294. return array(
  295. 'data' => $this->queue[$key][0],
  296. 'priority' => $key,
  297. );
  298. }
  299. /**
  300. * Iterator: is the current position valid for the queue
  301. *
  302. * @return bool
  303. */
  304. public function valid ()
  305. {
  306. return (bool)$this->count;
  307. }
  308. /**
  309. * Sort the queue
  310. *
  311. * @return void
  312. */
  313. protected function sort ()
  314. {
  315. krsort($this->queue);
  316. }
  317. /**
  318. * Prepare the queue for iteration and/or extraction
  319. *
  320. * @return void
  321. */
  322. protected function prepareQueue ()
  323. {
  324. $this->sort();
  325. $count = $this->count;
  326. $queue = array();
  327. foreach ($this->queue as $priority => $values) {
  328. $priorityKey = $priority;
  329. if (preg_match('/^(a|O):/', $priority)) {
  330. $priority = unserialize($priority);
  331. }
  332. foreach ($values as $key => $value) {
  333. $queue[$count] = array(
  334. 'data' => $value,
  335. 'priority' => $priority,
  336. 'priorityKey' => $priorityKey,
  337. 'key' => $key,
  338. );
  339. $count--;
  340. }
  341. }
  342. $this->preparedQueue = $queue;
  343. }
  344. }
  345. }
  346. /**
  347. * Serializable version of SplPriorityQueue
  348. *
  349. * Also, provides predictable heap order for datums added with the same priority
  350. * (i.e., they will be emitted in the same order they are enqueued).
  351. *
  352. * @category Zend
  353. * @package Zend_Stdlib
  354. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  355. * @license http://framework.zend.com/license/new-bsd New BSD License
  356. */
  357. class Zend_Stdlib_SplPriorityQueue extends SplPriorityQueue implements Serializable
  358. {
  359. /**
  360. * @var int Seed used to ensure queue order for items of the same priority
  361. */
  362. protected $serial = PHP_INT_MAX;
  363. /**
  364. * @var bool
  365. */
  366. protected $isPhp53;
  367. /**
  368. * Constructor
  369. *
  370. * @return void
  371. */
  372. public function __construct ()
  373. {
  374. $this->isPhp53 = version_compare(PHP_VERSION, '5.3', '>=');
  375. }
  376. /**
  377. * Insert a value with a given priority
  378. *
  379. * Utilizes {@var $serial} to ensure that values of equal priority are
  380. * emitted in the same order in which they are inserted.
  381. *
  382. * @param mixed $datum
  383. * @param mixed $priority
  384. *
  385. * @return void
  386. */
  387. public function insert ($datum, $priority)
  388. {
  389. // If using the native PHP SplPriorityQueue implementation, we need to
  390. // hack around it to ensure that items registered at the same priority
  391. // return in the order registered. In the userland version, this is not
  392. // necessary.
  393. if ($this->isPhp53) {
  394. if (!is_array($priority)) {
  395. $priority = array( $priority, $this->serial-- );
  396. }
  397. }
  398. parent::insert($datum, $priority);
  399. }
  400. /**
  401. * Serialize to an array
  402. *
  403. * Array will be priority => data pairs
  404. *
  405. * @return array
  406. */
  407. public function toArray ()
  408. {
  409. $this->setExtractFlags(self::EXTR_BOTH);
  410. $array = array();
  411. while ($this->valid()) {
  412. $array[] = $this->current();
  413. $this->next();
  414. }
  415. $this->setExtractFlags(self::EXTR_DATA);
  416. // Iterating through a priority queue removes items
  417. foreach ($array as $item) {
  418. $this->insert($item['data'], $item['priority']);
  419. }
  420. // Return only the data
  421. $return = array();
  422. foreach ($array as $item) {
  423. $return[] = $item['data'];
  424. }
  425. return $return;
  426. }
  427. /**
  428. * Serialize
  429. *
  430. * @return string
  431. */
  432. public function serialize ()
  433. {
  434. $data = array();
  435. $this->setExtractFlags(self::EXTR_BOTH);
  436. while ($this->valid()) {
  437. $data[] = $this->current();
  438. $this->next();
  439. }
  440. $this->setExtractFlags(self::EXTR_DATA);
  441. // Iterating through a priority queue removes items
  442. foreach ($data as $item) {
  443. $this->insert($item['data'], $item['priority']);
  444. }
  445. return serialize($data);
  446. }
  447. /**
  448. * Deserialize
  449. *
  450. * @param string $data
  451. *
  452. * @return void
  453. */
  454. public function unserialize ($data)
  455. {
  456. foreach (unserialize($data) as $item) {
  457. $this->insert($item['data'], $item['priority']);
  458. }
  459. }
  460. }