SplHeap, SplMinHeap, SplMaxHeap, SplPriorityQueue implementation

This commit is contained in:
Etienne Kneuss 2008-02-25 23:36:36 +00:00
parent cdb42ce6d2
commit cb51a84418
17 changed files with 2035 additions and 3 deletions

View file

@ -29,7 +29,7 @@ int main(int argc, char **argv) {
PHP_INSTALL_HEADERS([ext/spl/]) PHP_INSTALL_HEADERS([ext/spl/])
AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed]) AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed])
AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support]) AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c, no) PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c, no)
PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_sxe.h spl_dllist.h]) PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_sxe.h spl_dllist.h spl_heap.h])
PHP_ADD_EXTENSION_DEP(spl, pcre, true) PHP_ADD_EXTENSION_DEP(spl, pcre, true)
fi fi

View file

@ -7,6 +7,6 @@ if (PHP_SPL != "no") {
if (PHP_SPL_SHARED) { if (PHP_SPL_SHARED) {
ERROR("SPL cannot be compiled as a shared ext"); ERROR("SPL cannot be compiled as a shared ext");
} }
EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c"); EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c");
AC_DEFINE('HAVE_SPL', 1); AC_DEFINE('HAVE_SPL', 1);
} }

View file

@ -36,6 +36,7 @@
#include "spl_exceptions.h" #include "spl_exceptions.h"
#include "spl_observer.h" #include "spl_observer.h"
#include "spl_dllist.h" #include "spl_dllist.h"
#include "spl_heap.h"
#include "zend_exceptions.h" #include "zend_exceptions.h"
#include "zend_interfaces.h" #include "zend_interfaces.h"
#include "ext/standard/md5.h" #include "ext/standard/md5.h"
@ -151,6 +152,10 @@ PHP_FUNCTION(class_implements)
SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \
@ -768,6 +773,7 @@ PHP_MINIT_FUNCTION(spl)
PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_dllist)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_dllist)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
return SUCCESS; return SUCCESS;

1192
ext/spl/spl_heap.c Normal file

File diff suppressed because it is too large Load diff

44
ext/spl/spl_heap.h Normal file
View file

@ -0,0 +1,44 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2008 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Etienne Kneuss <colder@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef SPL_HEAP_H
#define SPL_HEAP_H
#include "php.h"
#include "php_spl.h"
PHPAPI zend_class_entry *spl_ce_SplHeap;
PHPAPI zend_class_entry *spl_ce_SplMinHeap;
PHPAPI zend_class_entry *spl_ce_SplMaxHeap;
PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
PHP_MINIT_FUNCTION(spl_heap);
#endif /* SPL_HEAP_H */
/*
* Local Variables:
* c-basic-offset: 4
* tab-width: 4
* End:
* vim600: fdm=marker
* vim: noet sw=4 ts=4
*/

View file

@ -0,0 +1,52 @@
--TEST--
SPL: SplMaxHeap: std operations
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$h = new SplMaxHeap();
// errors
try {
$h->extract();
} catch (RuntimeException $e) {
echo "Exception: ".$e->getMessage()."\n";
}
$h->insert(1);
$h->insert(2);
$h->insert(3);
$h->insert(3);
$h->insert(3);
echo $h->count()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->count()."\n";
echo "--\n";
$b = 4;
$h->insert($b);
$b = 5;
echo $h->extract()."\n";
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
Exception: Can't extract from an empty heap
5
3
3
3
2
1
0
--
4
===DONE===

View file

@ -0,0 +1,52 @@
--TEST--
SPL: SplMinHeap: std operations
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$h = new SplMinHeap();
// errors
try {
$h->extract();
} catch (RuntimeException $e) {
echo "Exception: ".$e->getMessage()."\n";
}
$h->insert(1);
$h->insert(2);
$h->insert(3);
$h->insert(3);
$h->insert(3);
echo $h->count()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->extract()."\n";
echo $h->count()."\n";
echo "--\n";
$b = 4;
$h->insert($b);
$b = 5;
echo $h->extract()."\n";
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
Exception: Can't extract from an empty heap
5
1
2
3
3
3
0
--
4
===DONE===

View file

@ -0,0 +1,46 @@
--TEST--
SPL: SplHeap: comparison callback
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class myHeap extends SplHeap {
public function compare($a, $b) {
if ($a > $b) {
$result = 1;
} else if ($a < $b) {
$result = -1;
} else {
$result = 0;
}
return $result;
}
}
$h = new myHeap;
$in = range(0,10);
shuffle($in);
foreach ($in as $i) {
$h->insert($i);
}
foreach ($h as $out) {
echo $out."\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
10
9
8
7
6
5
4
3
2
1
0
===DONE===

View file

@ -0,0 +1,69 @@
--TEST--
SPL: SplHeap: exceptions
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class myHeap extends SplHeap {
public function compare($a, $b) {
throw new exception("foo");
}
}
$h = new myHeap;
try {
$h->insert(1);
echo "inserted 1\n";
$h->insert(2);
echo "inserted 2\n";
$h->insert(3);
echo "inserted 3\n";
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
$h->insert(4);
echo "inserted 4\n";
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
echo "Recovering..\n";
$h->recoverFromCorruption();
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
inserted 1
Exception: foo
Exception: Heap is corrupted, heap properties are no longer ensured.
Exception: Heap is corrupted, heap properties are no longer ensured.
Exception: Heap is corrupted, heap properties are no longer ensured.
Recovering..
int(1)
int(2)
===DONE===

123
ext/spl/tests/heap_005.phpt Normal file
View file

@ -0,0 +1,123 @@
--TEST--
SPL: SplMinHeap: large unordered input iterated
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$input = range(1,100);
shuffle($input);
$h = new SplMinHeap();
foreach($input as $i) {
$h->insert($i);
}
foreach ($h as $k => $o) {
echo "$k => $o\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
100 => 1
99 => 2
98 => 3
97 => 4
96 => 5
95 => 6
94 => 7
93 => 8
92 => 9
91 => 10
90 => 11
89 => 12
88 => 13
87 => 14
86 => 15
85 => 16
84 => 17
83 => 18
82 => 19
81 => 20
80 => 21
79 => 22
78 => 23
77 => 24
76 => 25
75 => 26
74 => 27
73 => 28
72 => 29
71 => 30
70 => 31
69 => 32
68 => 33
67 => 34
66 => 35
65 => 36
64 => 37
63 => 38
62 => 39
61 => 40
60 => 41
59 => 42
58 => 43
57 => 44
56 => 45
55 => 46
54 => 47
53 => 48
52 => 49
51 => 50
50 => 51
49 => 52
48 => 53
47 => 54
46 => 55
45 => 56
44 => 57
43 => 58
42 => 59
41 => 60
40 => 61
39 => 62
38 => 63
37 => 64
36 => 65
35 => 66
34 => 67
33 => 68
32 => 69
31 => 70
30 => 71
29 => 72
28 => 73
27 => 74
26 => 75
25 => 76
24 => 77
23 => 78
22 => 79
21 => 80
20 => 81
19 => 82
18 => 83
17 => 84
16 => 85
15 => 86
14 => 87
13 => 88
12 => 89
11 => 90
10 => 91
9 => 92
8 => 93
7 => 94
6 => 95
5 => 96
4 => 97
3 => 98
2 => 99
1 => 100
===DONE===

123
ext/spl/tests/heap_006.phpt Normal file
View file

@ -0,0 +1,123 @@
--TEST--
SPL: SplMaxHeap: large unordered input iterated
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$input = range(1,100);
shuffle($input);
$h = new SplMaxHeap();
foreach($input as $i) {
$h->insert($i);
}
foreach ($h as $k => $o) {
echo "$k => $o\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
100 => 100
99 => 99
98 => 98
97 => 97
96 => 96
95 => 95
94 => 94
93 => 93
92 => 92
91 => 91
90 => 90
89 => 89
88 => 88
87 => 87
86 => 86
85 => 85
84 => 84
83 => 83
82 => 82
81 => 81
80 => 80
79 => 79
78 => 78
77 => 77
76 => 76
75 => 75
74 => 74
73 => 73
72 => 72
71 => 71
70 => 70
69 => 69
68 => 68
67 => 67
66 => 66
65 => 65
64 => 64
63 => 63
62 => 62
61 => 61
60 => 60
59 => 59
58 => 58
57 => 57
56 => 56
55 => 55
54 => 54
53 => 53
52 => 52
51 => 51
50 => 50
49 => 49
48 => 48
47 => 47
46 => 46
45 => 45
44 => 44
43 => 43
42 => 42
41 => 41
40 => 40
39 => 39
38 => 38
37 => 37
36 => 36
35 => 35
34 => 34
33 => 33
32 => 32
31 => 31
30 => 30
29 => 29
28 => 28
27 => 27
26 => 26
25 => 25
24 => 24
23 => 23
22 => 22
21 => 21
20 => 20
19 => 19
18 => 18
17 => 17
16 => 16
15 => 15
14 => 14
13 => 13
12 => 12
11 => 11
10 => 10
9 => 9
8 => 8
7 => 7
6 => 6
5 => 5
4 => 4
3 => 3
2 => 2
1 => 1
===DONE===

View file

@ -0,0 +1,33 @@
--TEST--
SPL: SplHeap: iteration through methods
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$h = new SplMaxHeap();
$h->insert(1);
$h->insert(5);
$h->insert(0);
$h->insert(4);
$h->rewind();
echo "count(\$h) = ".count($h)."\n";
echo "\$h->count() = ".$h->count()."\n";
while ($h->valid()) {
$k = $h->key();
$v = $h->current();
echo "$k=>$v\n";
$h->next();
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
count($h) = 4
$h->count() = 4
4=>5
3=>4
2=>1
1=>0
===DONE===

View file

@ -0,0 +1,36 @@
--TEST--
SPL: SplHeap: var_dump
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$h = new SplMaxHeap();
$h->insert(1);
$h->insert(5);
$h->insert(0);
$h->insert(4);
var_dump($h);
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
object(SplMaxHeap)#1 (3) {
["flags":"SplHeap":private]=>
int(0)
["isCorrupted":"SplHeap":private]=>
bool(false)
["heap":"SplHeap":private]=>
array(4) {
[0]=>
int(5)
[1]=>
int(4)
[2]=>
int(0)
[3]=>
int(1)
}
}
===DONE===

View file

@ -0,0 +1,98 @@
--TEST--
SPL: SplPriorityQueue: std operations and extract flags
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$pq = new SplPriorityQueue();
// errors
try {
$pq->extract();
} catch (RuntimeException $e) {
echo "Exception: ".$e->getMessage()."\n";
}
$pq->insert("a", 1);
$pq->insert("b", 2);
$pq->insert("c", 0);
foreach ($pq as $k=>$v) {
echo "$k=>".print_r($v, 1)."\n";
}
echo "EXTR_BOTH\n";
$pq1 = new SplPriorityQueue();
$pq1->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
$pq1->insert("a", 1);
$pq1->insert("b", 2);
$pq1->insert("c", 0);
foreach ($pq1 as $k=>$v) {
echo "$k=>".print_r($v, 1)."\n";
}
echo "EXTR_DATA\n";
$pq2 = new SplPriorityQueue();
$pq2->setExtractFlags(SplPriorityQueue::EXTR_DATA);
$pq2->insert("a", 1);
$pq2->insert("b", 2);
$pq2->insert("c", 0);
foreach ($pq2 as $k=>$v) {
echo "$k=>".print_r($v, 1)."\n";
}
echo "EXTR_PRIORITY\n";
$pq3 = new SplPriorityQueue();
$pq3->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
$pq3->insert("a", 1);
$pq3->insert("b", 2);
$pq3->insert("c", 0);
foreach ($pq3 as $k=>$v) {
echo "$k=>".print_r($v, 1)."\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
Exception: Can't extract from an empty heap
3=>b
2=>a
1=>c
EXTR_BOTH
3=>Array
(
[data] => b
[priority] => 2
)
2=>Array
(
[data] => a
[priority] => 1
)
1=>Array
(
[data] => c
[priority] => 0
)
EXTR_DATA
3=>b
2=>a
1=>c
EXTR_PRIORITY
3=>2
2=>1
1=>0
===DONE===

View file

@ -0,0 +1,69 @@
--TEST--
SPL: SplPriorityQueue: exceptions
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
class myPQueue extends SplPriorityQueue {
public function compare($a, $b) {
throw new exception("foo");
}
}
$h = new myPQueue;
try {
$h->insert(1, 1);
echo "inserted 1\n";
$h->insert(2, 1);
echo "inserted 2\n";
$h->insert(3, 1);
echo "inserted 3\n";
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
$h->insert(4, 1);
echo "inserted 4\n";
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
echo "Recovering..\n";
$h->recoverFromCorruption();
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
try {
var_dump($h->extract());
} catch(Exception $e) {
echo "Exception: ".$e->getMessage()."\n";
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
inserted 1
Exception: foo
Exception: Heap is corrupted, heap properties are no longer ensured.
Exception: Heap is corrupted, heap properties are no longer ensured.
Exception: Heap is corrupted, heap properties are no longer ensured.
Recovering..
int(1)
int(2)
===DONE===

View file

@ -0,0 +1,33 @@
--TEST--
SPL: SplPriorityQueue: iteration through methods
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$h = new SplPriorityQueue();
$h->insert(1, 1);
$h->insert(5, 5);
$h->insert(0, 0);
$h->insert(4, 4);
$h->rewind();
echo "count(\$h) = ".count($h)."\n";
echo "\$h->count() = ".$h->count()."\n";
while ($h->valid()) {
$k = $h->key();
$v = $h->current();
echo "$k=>$v\n";
$h->next();
}
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
count($h) = 4
$h->count() = 4
4=>5
3=>4
2=>1
1=>0
===DONE===

View file

@ -0,0 +1,56 @@
--TEST--
SPL: SplPriorityQueue: var_dump
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
$pq = new SplPriorityQueue();
$pq->insert("a", 0);
$pq->insert("b", 1);
$pq->insert("c", 5);
$pq->insert("d", -2);
var_dump($pq);
?>
===DONE===
<?php exit(0); ?>
--EXPECTF--
object(SplPriorityQueue)#1 (3) {
["flags":"SplPriorityQueue":private]=>
int(1)
["isCorrupted":"SplPriorityQueue":private]=>
bool(false)
["heap":"SplPriorityQueue":private]=>
array(4) {
[0]=>
array(2) {
["data"]=>
string(1) "c"
["priority"]=>
int(5)
}
[1]=>
array(2) {
["data"]=>
string(1) "a"
["priority"]=>
int(0)
}
[2]=>
array(2) {
["data"]=>
string(1) "b"
["priority"]=>
int(1)
}
[3]=>
array(2) {
["data"]=>
string(1) "d"
["priority"]=>
int(-2)
}
}
}
===DONE===