├── TODO ├── CREDITS ├── config.w32 ├── config.m4 ├── composer.json ├── .gitignore ├── tests ├── BitSet_xorOp.phpt ├── BitSet_andNotOp.phpt ├── BitSet_orOp.phpt ├── BitSet_andOp.phpt ├── BitSet_size.phpt ├── BitSet_isEmpty.phpt ├── BitSet_getRawValue.phpt ├── bug63315.phpt ├── BitSet_fromRawValue.phpt ├── BitSet_cardinality.phpt ├── BitSet_toArray.phpt ├── BitSet_length.phpt ├── BitSet_get.phpt ├── BitSet_intersects.phpt ├── BitSet_fromString.phpt ├── BitSet_nextSetBit.phpt ├── BitSet_nextClearBit.phpt ├── BitSet_construct.phpt ├── BitSet_fromArray.phpt ├── BitSet_fromInteger.phpt ├── BitSet_set.phpt ├── BitSet_previousClearBit.phpt ├── BitSet_previousSetBit.phpt └── BitSet_clear.phpt ├── README ├── bitset.stub.php ├── php_bitset.h ├── LICENSE ├── bitset.dsp ├── bitset_legacy_arginfo.h ├── package.xml ├── bitset_arginfo.h └── bitset.c /TODO: -------------------------------------------------------------------------------- 1 | - documentation 2 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | BitSet 2 | Will Fitch, Alexander Veremyev, Remi Collet 3 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | ARG_ENABLE("bitset", "enable bitset support", "no"); 5 | 6 | if (PHP_BITSET != "no") { 7 | EXTENSION("bitset", "bitset.c"); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension bitset 3 | 4 | CFLAGS="${CFLAGS} -Wall" 5 | 6 | PHP_ARG_ENABLE(bitset, whether to enable bitset support, [ --enable-bitset Enable bitset support]) 7 | 8 | if test "$PHP_BITSET" != "no"; then 9 | PHP_NEW_EXTENSION(bitset, bitset.c, $ext_shared) 10 | fi 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pecl/bitset", 3 | "type": "php-ext", 4 | "license": "PHP-3.01", 5 | "description": "BITSET extension", 6 | "require": { 7 | "php": ">= 7.0.0" 8 | }, 9 | "php-ext": { 10 | "extension-name": "bitset", 11 | "configure-options": [] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.lo 3 | *.a 4 | *.loT 5 | Makefile* 6 | auto* 7 | configure* 8 | config.h* 9 | config.log 10 | config.guess 11 | config.nice 12 | config.status 13 | missing 14 | ltmain* 15 | install-sh 16 | mkinstalldirs 17 | build 18 | config.sub 19 | aclocal* 20 | acinclude* 21 | libtool 22 | .libs 23 | .deps 24 | *.dep 25 | *.la 26 | modules 27 | run-tests.php 28 | 29 | -------------------------------------------------------------------------------- /tests/BitSet_xorOp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::xorOp() - Test that logical XOR operations actually work 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(2); 10 | $b->set(6); 11 | $c->set(2); 12 | $b->xorOp($c); 13 | var_dump($b->__toString()); 14 | ?> 15 | --EXPECT-- 16 | string(64) "0000001000000000000000000000000000000000000000000000000000000000" 17 | -------------------------------------------------------------------------------- /tests/BitSet_andNotOp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::andNotOp() - Test that switching set bits to off with input BitSet 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(2); 10 | $b->set(6); 11 | $c->set(2); 12 | $b->andNotOp($c); 13 | var_dump($b->__toString()); 14 | ?> 15 | --EXPECT-- 16 | string(64) "0000001000000000000000000000000000000000000000000000000000000000" 17 | -------------------------------------------------------------------------------- /tests/BitSet_orOp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::orOp() - Test that logical OR operations actually work 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(2); 10 | $b->set(6); 11 | $c->set(2); 12 | $c->set(9); 13 | $b->orOp($c); 14 | var_dump($b->__toString()); 15 | ?> 16 | --EXPECT-- 17 | string(64) "0010001001000000000000000000000000000000000000000000000000000000" 18 | -------------------------------------------------------------------------------- /tests/BitSet_andOp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::andOp() - Test that logical AND operations actually work 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(2); 9 | $b->set(6); 10 | $c = new BitSet(); 11 | $c->set(2); 12 | $c->set(50); 13 | $b->andOp($c); 14 | var_dump($b->__toString()); 15 | ?> 16 | --EXPECT-- 17 | string(64) "0010000000000000000000000000000000000000000000000000000000000000" 18 | -------------------------------------------------------------------------------- /tests/BitSet_size.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::size() - Tests to verify the total bits are maintained and correctly represented 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | size()); 9 | 10 | $b = new BitSet(8); 11 | $b->set(2, 4); 12 | $b->clear(3); 13 | var_dump($b->size()); 14 | 15 | $b = new BitSet(2048); 16 | var_dump($b->size()); 17 | ?> 18 | --EXPECT-- 19 | int(64) 20 | int(8) 21 | int(2048) 22 | -------------------------------------------------------------------------------- /tests/BitSet_isEmpty.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::isEmpty() - Verifies that isEmpty truly checks for all off bits 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | isEmpty()); 9 | 10 | $b->set(32); 11 | var_dump($b->isEmpty()); 12 | 13 | $b->clear(32); 14 | $b->set(40); 15 | $b->clear(40); 16 | var_dump($b->isEmpty()); 17 | ?> 18 | --EXPECT-- 19 | bool(true) 20 | bool(false) 21 | bool(true) 22 | 23 | -------------------------------------------------------------------------------- /tests/BitSet_getRawValue.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::getRawValue() - Verifies the binary string returned is as expected and integrity is maintained 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | getRawValue())); 9 | 10 | $b->set(5); 11 | var_dump(base64_encode($b->getRawValue())); 12 | var_dump(bin2hex($b->getRawValue())); 13 | ?> 14 | --EXPECT-- 15 | string(4) "AA==" 16 | string(4) "IA==" 17 | string(2) "20" 18 | -------------------------------------------------------------------------------- /tests/bug63315.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #63315 (BitSet::fromArray may modify original array value) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 12 | --EXPECT-- 13 | array(3) { 14 | [0]=> 15 | int(5) 16 | [1]=> 17 | int(6) 18 | [2]=> 19 | string(1) "7" 20 | } 21 | array(3) { 22 | [0]=> 23 | int(5) 24 | [1]=> 25 | int(6) 26 | [2]=> 27 | string(1) "7" 28 | } 29 | -------------------------------------------------------------------------------- /tests/BitSet_fromRawValue.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::fromRawValue() - Verifies the provided input raw value is represented in set bits 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 9 | $b = BitSet::fromRawValue(base64_decode('IA==')); 10 | var_dump($b->__toString()); 11 | var_dump(base64_encode($b->getRawValue())); 12 | ?> 13 | --EXPECT-- 14 | string(8) "00000000" 15 | string(8) "00000100" 16 | string(4) "IA==" 17 | 18 | -------------------------------------------------------------------------------- /tests/BitSet_cardinality.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::cardinality() - Verifies all true bits that are set are correctly counted 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(5); 9 | $b->set(33); 10 | $b->set(63); 11 | 12 | var_dump($b->cardinality()); 13 | 14 | $b->clear(63); 15 | 16 | var_dump($b->cardinality()); 17 | 18 | $b->set(32); 19 | $b->clear(33); 20 | 21 | var_dump($b->cardinality()); 22 | ?> 23 | --EXPECT-- 24 | int(3) 25 | int(2) 26 | int(2) 27 | 28 | -------------------------------------------------------------------------------- /tests/BitSet_toArray.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::toArray() - Verifies set bits are correctly returned in the array 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(5); 9 | $b->set(22); 10 | var_dump($b->toArray()); 11 | 12 | $b->clear(22); 13 | $b->set(36); 14 | var_dump($b->toArray()); 15 | ?> 16 | --EXPECT-- 17 | array(2) { 18 | [0]=> 19 | int(5) 20 | [1]=> 21 | int(22) 22 | } 23 | array(2) { 24 | [0]=> 25 | int(5) 26 | [1]=> 27 | int(36) 28 | } 29 | -------------------------------------------------------------------------------- /tests/BitSet_length.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::length() - Verifies the highest bit + 1 is returned 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | length()); 9 | 10 | $b->set(0); 11 | var_dump($b->length()); 12 | 13 | $b->set(33); 14 | var_dump($b->length()); 15 | 16 | $b->set(22); 17 | var_dump($b->length()); 18 | 19 | $b->set(55); 20 | var_dump($b->length()); 21 | 22 | $b->clear(55); 23 | var_dump($b->length()); 24 | ?> 25 | --EXPECT-- 26 | int(0) 27 | int(1) 28 | int(34) 29 | int(34) 30 | int(56) 31 | int(34) 32 | 33 | -------------------------------------------------------------------------------- /tests/BitSet_get.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::get() - Verifies integrity of bit index retrieval 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(5); 9 | var_dump($b->get(0)); 10 | var_dump($b->get(5)); 11 | var_dump($b->get(20)); 12 | $b->set(20); 13 | var_dump($b->get(20)); 14 | try { 15 | var_dump($b->get(64)); 16 | } catch (Exception $e) { 17 | echo get_class($e).'-'.$e->getMessage()."\n"; 18 | } 19 | ?> 20 | --EXPECT-- 21 | bool(false) 22 | bool(true) 23 | bool(false) 24 | bool(true) 25 | OutOfRangeException-The specified index parameter exceeds the total number of bits available 26 | -------------------------------------------------------------------------------- /tests/BitSet_intersects.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::intersects() - if the provided value has any bits set to true that are also true in this object 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | intersects($c)); // false 10 | var_dump($c->intersects($b)); // false 11 | $b->set(2); 12 | $c->set(10); 13 | var_dump($b->intersects($c)); // false 14 | var_dump($c->intersects($b)); // false 15 | $b->set(10); 16 | var_dump($b->intersects($c)); // true 17 | var_dump($c->intersects($b)); // true 18 | ?> 19 | --EXPECT-- 20 | bool(false) 21 | bool(false) 22 | bool(false) 23 | bool(false) 24 | bool(true) 25 | bool(true) 26 | -------------------------------------------------------------------------------- /tests/BitSet_fromString.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::fromString() - Verifies BitSet correctly parses incoming strings to its binary representation 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 9 | 10 | $b = BitSet::fromString('0010000010'); 11 | var_dump($b->__toString()); 12 | 13 | $b = BitSet::fromString('0200100010'); 14 | var_dump($b->__toString()); 15 | 16 | $b = BitSet::fromString(''); 17 | var_dump($b->__toString()); 18 | ?> 19 | --EXPECT-- 20 | string(8) "01100000" 21 | string(16) "0010000010000000" 22 | string(16) "0000100010000000" 23 | string(64) "0000000000000000000000000000000000000000000000000000000000000000" 24 | -------------------------------------------------------------------------------- /tests/BitSet_nextSetBit.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::nextSetBit() - Verifies the next set bit is valid based on the provided index 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(20); 9 | $b->set(18); 10 | var_dump($b->nextSetBit(0)); 11 | var_dump($b->nextSetBit(20)); 12 | var_dump($b->nextSetBit(18)); 13 | var_dump($b->nextSetBit(5)); 14 | try { 15 | var_dump($b->nextSetBit(63)); 16 | } catch (Exception $e) { 17 | echo get_class($e).': '.$e->getMessage()."\n"; 18 | } 19 | 20 | ?> 21 | --EXPECT-- 22 | int(18) 23 | bool(false) 24 | int(20) 25 | int(18) 26 | InvalidArgumentException: There are no bits larger than the index provided 27 | -------------------------------------------------------------------------------- /tests/BitSet_nextClearBit.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::nextClearBit() - Verifies the next clear bit is valid based on the provided index 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(20); 9 | $b->set(18); 10 | var_dump($b->nextClearBit(0)); 11 | var_dump($b->nextClearBit(20)); 12 | var_dump($b->nextClearBit(18)); 13 | var_dump($b->nextClearBit(5)); 14 | try { 15 | var_dump($b->nextClearBit(63)); 16 | } catch (Exception $e) { 17 | echo get_class($e).': '.$e->getMessage()."\n"; 18 | } 19 | ?> 20 | --EXPECT-- 21 | int(1) 22 | int(21) 23 | int(19) 24 | int(6) 25 | InvalidArgumentException: There are no bits larger than the index provided 26 | -------------------------------------------------------------------------------- /tests/BitSet_construct.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::__construct() - Generic constructor tests 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 10 | 11 | // Verify we get 8 bits that are off 12 | $b = new BitSet(8); 13 | var_dump($b->__toString()); 14 | 15 | /* Regardless of the value specified in the constructor, it should 16 | * always be rounded to the nearest byte in size 17 | */ 18 | $b = new BitSet(12); // CHAR_BIT = 8, so we should have 16 bits 19 | var_dump($b->__toString()); 20 | ?> 21 | --EXPECT-- 22 | string(64) "0000000000000000000000000000000000000000000000000000000000000000" 23 | string(8) "00000000" 24 | string(16) "0000000000000000" 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | BITSET 2 | Released under the PHP License 3.01 3 | 4 | The BitSet extension assists by providing a mechanism to manage sets of bits. 5 | This provides a similar API (object-based) to java.util.BitSet with some 6 | PHP-specific flavoring. 7 | 8 | 9 | IMPORTANT 10 | --------- 11 | Versions 3.0 and higher of this extension require PHP 7+ 12 | 13 | 14 | COMPILATION 15 | ----------- 16 | 17 | - Uncompress the tarball or clone the git repository 18 | - Run phpize 19 | - Run ./configure [--enable-bitset] 20 | - Run make, then make install. 21 | - Add the extension loading directive to your php.ini 22 | extension=bitset.so 23 | 24 | 25 | INSTALLATION FROM PECL 26 | ---------------------- 27 | 28 | - pecl install bitset 29 | 30 | 31 | REPORTING BUGS 32 | -------------- 33 | 34 | Please report all bugs at https://github.com/php/pecl-numbers-bitset/issues 35 | -------------------------------------------------------------------------------- /tests/BitSet_fromArray.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::fromArray() - Verifies the provided input array is represented in set bits 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 10 | var_dump($b->toArray()); 11 | 12 | $b = BitSet::fromArray([0]); 13 | var_dump($b->__toString()); 14 | var_dump($b->toArray()); 15 | 16 | $b = BitSet::fromArray([7]); 17 | var_dump($b->__toString()); 18 | var_dump($b->toArray()); 19 | ?> 20 | --EXPECT-- 21 | string(24) "011000100000000001000000" 22 | array(4) { 23 | [0]=> 24 | int(1) 25 | [1]=> 26 | int(2) 27 | [2]=> 28 | int(6) 29 | [3]=> 30 | int(17) 31 | } 32 | string(8) "10000000" 33 | array(1) { 34 | [0]=> 35 | int(0) 36 | } 37 | string(8) "00000001" 38 | array(1) { 39 | [0]=> 40 | int(7) 41 | } 42 | 43 | -------------------------------------------------------------------------------- /tests/BitSet_fromInteger.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::fromInteger() - Verifies the provided value is represented in set bits 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 9 | var_dump($b->toInteger()); 10 | 11 | $b = BitSet::fromInteger(42); 12 | var_dump($b->__toString()); 13 | var_dump($b->toInteger()); 14 | 15 | $b = BitSet::fromInteger(0x010203); 16 | var_dump($b->__toString()); 17 | var_dump($b->toInteger()); 18 | 19 | $b = new BitSet(80); 20 | try { 21 | var_dump($b->toInteger()); 22 | } catch (InvalidArgumentException $e) { 23 | echo "Exception: " . $e->getMessage() . "\n"; 24 | } 25 | 26 | ?> 27 | --EXPECTF-- 28 | string(%d) "0000000000000000000%s" 29 | int(0) 30 | string(%d) "0101010000000000000%s" 31 | int(42) 32 | string(%d) "1100000001000000100%s" 33 | int(66051) 34 | Exception: The total bits doesn't fit in an integer 35 | 36 | -------------------------------------------------------------------------------- /tests/BitSet_set.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::set() - Tests for setting bits or a range of bits on 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | __toString()); 9 | $b->set(2); 10 | var_dump($b->__toString()); 11 | 12 | $b->set(2, 4); 13 | var_dump($b->__toString()); 14 | 15 | $b->set(0); 16 | var_dump($b->__toString()); 17 | 18 | $b->set(7); 19 | var_dump($b->__toString()); 20 | 21 | $b->set(); // Set all bits on 22 | var_dump($b->__toString()); 23 | 24 | try { 25 | var_dump($b->set(8)); 26 | } catch (Exception $e) { 27 | var_dump(get_class($e).': '.$e->getMessage()); 28 | } 29 | ?> 30 | --EXPECT-- 31 | string(8) "00000000" 32 | string(8) "00100000" 33 | string(8) "00111000" 34 | string(8) "10111000" 35 | string(8) "10111001" 36 | string(8) "11111111" 37 | string(87) "OutOfRangeException: The requested start index is greater than the total number of bits" 38 | -------------------------------------------------------------------------------- /tests/BitSet_previousClearBit.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::previousClearBit() - Verifies the previous clear bit is valid based on the provided index 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(20); 9 | $b->set(18); 10 | try { 11 | var_dump($b->previousClearBit(0)); 12 | } catch (Exception $e) { 13 | var_dump(get_class($e).': '.$e->getMessage()); 14 | } 15 | var_dump($b->previousClearBit(20)); 16 | var_dump($b->previousClearBit(18)); 17 | var_dump($b->previousClearBit(5)); 18 | try { 19 | var_dump($b->previousClearBit(65)); 20 | } catch (Exception $e) { 21 | var_dump(get_class($e).': '.$e->getMessage()); 22 | } 23 | ?> 24 | --EXPECT-- 25 | string(75) "InvalidArgumentException: There are no bits smaller than the index provided" 26 | int(19) 27 | int(17) 28 | int(4) 29 | string(93) "OutOfRangeException: The specified index parameter exceeds the total number of bits available" 30 | -------------------------------------------------------------------------------- /tests/BitSet_previousSetBit.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::previousSetBit() - Verifies the previous set bit is valid based on the provided index 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(20); 9 | $b->set(18); 10 | try { 11 | var_dump($b->previousSetBit(0)); 12 | } catch (Exception $e) { 13 | var_dump(get_class($e).': '.$e->getMessage()); 14 | } 15 | var_dump($b->previousSetBit(20)); 16 | var_dump($b->previousSetBit(18)); 17 | $b->set(1); 18 | var_dump($b->previousSetBit(5)); 19 | try { 20 | var_dump($b->previousSetBit(65)); 21 | } catch (Exception $e) { 22 | var_dump(get_class($e).': '.$e->getMessage()); 23 | } 24 | ?> 25 | --EXPECT-- 26 | string(75) "InvalidArgumentException: There are no bits smaller than the index provided" 27 | int(18) 28 | bool(false) 29 | int(1) 30 | string(93) "OutOfRangeException: The specified index parameter exceeds the total number of bits available" 31 | 32 | -------------------------------------------------------------------------------- /tests/BitSet_clear.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | BitSet BitSet::clear() - Test clearing bits individually, as sets and as a whole 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | set(50); 9 | $b->set(63); 10 | var_dump($b->get(50)); 11 | $b->clear(50); 12 | var_dump($b->get(50)); 13 | $b->clear(); 14 | var_dump($b->__toString()); 15 | 16 | $b->set(5); 17 | $b->set(10); 18 | $b->set(20); 19 | $b->clear(5, 11); 20 | var_dump($b->__toString()); 21 | 22 | $b->set(0, 1); 23 | $b->clear(0); 24 | var_dump($b->__toString()); 25 | try { 26 | var_dump($b->clear(64)); 27 | } catch (Exception $e) { 28 | echo get_class($e).': '.$e->getMessage()."\n"; 29 | } 30 | ?> 31 | --EXPECT-- 32 | bool(true) 33 | bool(false) 34 | string(64) "0000000000000000000000000000000000000000000000000000000000000000" 35 | string(64) "0000000000000000000010000000000000000000000000000000000000000000" 36 | string(64) "0100000000000000000010000000000000000000000000000000000000000000" 37 | OutOfRangeException: The requested start index is greater than the total number of bits -------------------------------------------------------------------------------- /bitset.stub.php: -------------------------------------------------------------------------------- 1 | | 14 | | Alexander Veremyev | 15 | | Remi Collet | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef PHP_BITSET_H 20 | #define PHP_BITSET_H 21 | 22 | #define phpext_bitset_ptr &bitset_module_entry 23 | extern zend_module_entry bitset_module_entry; 24 | 25 | #define PHP_BITSET_VERSION "3.2.1-dev" 26 | 27 | #ifdef PHP_WIN32 28 | #define PHP_BITSET_API __declspec(dllexport) 29 | #else 30 | #define PHP_BITSET_API 31 | #endif 32 | 33 | #ifdef ZTS 34 | #include "TSRM.h" 35 | #endif 36 | 37 | #define BITSET_DEFAULT_BITS 64 38 | 39 | typedef struct { 40 | unsigned char *bitset_val; 41 | unsigned long bitset_len; 42 | zend_object zo; 43 | } php_bitset_object; 44 | 45 | PHP_MINIT_FUNCTION(bitset); 46 | PHP_MSHUTDOWN_FUNCTION(bitset); 47 | PHP_MINFO_FUNCTION(bitset); 48 | 49 | static inline php_bitset_object *php_bitset_fetch_object(zend_object *obj) 50 | { 51 | return (php_bitset_object *)((char *)(obj) - XtOffsetOf(php_bitset_object, zo)); 52 | } 53 | 54 | #endif 55 | 56 | /* 57 | * Local variables: 58 | * tab-width: 4 59 | * c-basic-offset: 4 60 | * End: 61 | * vim600: noet sw=4 ts=4 fdm=marker 62 | * vim<600: noet sw=4 ts=4 63 | */ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2014 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /bitset.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="bitset" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 6 | 7 | CFG=bitset - Win32 Debug_TS 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "bitset.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "bitset.mak" CFG="bitset - Win32 Debug_TS" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "bitset - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") 21 | !MESSAGE "bitset - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | MTL=midl.exe 30 | RSC=rc.exe 31 | 32 | !IF "$(CFG)" == "bitset - Win32 Debug_TS" 33 | 34 | # PROP BASE Use_MFC 0 35 | # PROP BASE Use_Debug_Libraries 1 36 | # PROP BASE Output_Dir "Debug_TS" 37 | # PROP BASE Intermediate_Dir "Debug_TS" 38 | # PROP BASE Target_Dir "" 39 | # PROP Use_MFC 0 40 | # PROP Use_Debug_Libraries 1 41 | # PROP Output_Dir "Debug_TS" 42 | # PROP Intermediate_Dir "Debug_TS" 43 | # PROP Ignore_Export_Lib 0 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BITSET_EXPORTS" /YX /FD /GZ /c 46 | # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\main" /I "..\..\TSRM" /I "..\..\ZEND" /D ZEND_WIN32=1 /D PHP_WIN32=1 /D "NDEBUG" /D "PHP_EXPORTS" /D "HAVE_BITSET" /D COMPILE_DL_BITSET=1 /D ZEND_DEBUG=0 /D "ZTS" /YX /FD /GZ /c 47 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 48 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 49 | # ADD BASE RSC /l 0x407 /d "_DEBUG" 50 | # ADD RSC /l 0x407 /d "_DEBUG" 51 | BSC32=bscmake.exe 52 | # ADD BASE BSC32 /nologo 53 | # ADD BSC32 /nologo 54 | LINK32=link.exe 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept 56 | # ADD LINK32 php5ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_bitset.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" 57 | 58 | !ELSEIF "$(CFG)" == "bitset - Win32 Release_TS" 59 | 60 | # PROP BASE Use_MFC 0 61 | # PROP BASE Use_Debug_Libraries 0 62 | # PROP BASE Output_Dir "Release_TS" 63 | # PROP BASE Intermediate_Dir "Release_TS" 64 | # PROP BASE Target_Dir "" 65 | # PROP Use_MFC 0 66 | # PROP Use_Debug_Libraries 0 67 | # PROP Output_Dir "Release_TS" 68 | # PROP Intermediate_Dir "Release_TS" 69 | # PROP Ignore_Export_Lib 0 70 | # PROP Target_Dir "" 71 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BITSET_EXPORTS" /YX /FD /c 72 | # ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\\" /I "..\..\main" /I "..\..\TSRM" /I "..\..\ZEND" /I "include" /D ZEND_WIN32=1 /D PHP_WIN32=1 /D "NDEBUG" /D "PHP_EXPORTS" /D "HAVE_BITSET" /D COMPILE_DL_BITSET=1 /D ZEND_DEBUG=0 /D "ZTS" /D "WIN32" /FR /YX /FD /c 73 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 74 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 75 | # ADD BASE RSC /l 0x407 /d "NDEBUG" 76 | # ADD RSC /l 0x407 /d "NDEBUG" 77 | BSC32=bscmake.exe 78 | # ADD BASE BSC32 /nologo 79 | # ADD BSC32 /nologo 80 | LINK32=link.exe 81 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 82 | # ADD LINK32 php5ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_bitset.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"lib" 83 | 84 | !ENDIF 85 | 86 | # Begin Target 87 | 88 | # Name "bitset - Win32 Debug_TS" 89 | # Name "bitset - Win32 Release_TS" 90 | # Begin Group "Source Files" 91 | 92 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 93 | # Begin Source File 94 | 95 | SOURCE=.\bitset.c 96 | # End Source File 97 | # End Group 98 | # Begin Group "Header Files" 99 | 100 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 101 | # Begin Source File 102 | 103 | SOURCE=.\php_bitset.h 104 | # End Source File 105 | # End Group 106 | # End Target 107 | # End Project 108 | -------------------------------------------------------------------------------- /bitset_legacy_arginfo.h: -------------------------------------------------------------------------------- 1 | /* This is a generated file, edit the .stub.php file instead. 2 | * Stub hash: 8da3818a0101d81ea3e553f6c3afbe1773ce2c55 */ 3 | 4 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet___construct, 0, 0, 0) 5 | ZEND_ARG_INFO(0, value) 6 | ZEND_END_ARG_INFO() 7 | 8 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_andOp, 0, 0, 1) 9 | ZEND_ARG_INFO(0, set) 10 | ZEND_END_ARG_INFO() 11 | 12 | #define arginfo_class_BitSet_andNotOp arginfo_class_BitSet_andOp 13 | 14 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_cardinality, 0, 0, 0) 15 | ZEND_END_ARG_INFO() 16 | 17 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_clear, 0, 0, 0) 18 | ZEND_ARG_INFO(0, from) 19 | ZEND_ARG_INFO(0, to) 20 | ZEND_END_ARG_INFO() 21 | 22 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_fromArray, 0, 0, 1) 23 | ZEND_ARG_INFO(0, arr) 24 | ZEND_END_ARG_INFO() 25 | 26 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_fromInteger, 0, 0, 1) 27 | ZEND_ARG_INFO(0, value) 28 | ZEND_END_ARG_INFO() 29 | 30 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_fromString, 0, 0, 1) 31 | ZEND_ARG_INFO(0, str) 32 | ZEND_END_ARG_INFO() 33 | 34 | #define arginfo_class_BitSet_fromRawValue arginfo_class_BitSet_fromString 35 | 36 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_get, 0, 0, 1) 37 | ZEND_ARG_INFO(0, index) 38 | ZEND_END_ARG_INFO() 39 | 40 | #define arginfo_class_BitSet_getRawValue arginfo_class_BitSet_cardinality 41 | 42 | #define arginfo_class_BitSet_intersects arginfo_class_BitSet_andOp 43 | 44 | #define arginfo_class_BitSet_isEmpty arginfo_class_BitSet_cardinality 45 | 46 | #define arginfo_class_BitSet_length arginfo_class_BitSet_cardinality 47 | 48 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet_nextClearBit, 0, 0, 1) 49 | ZEND_ARG_INFO(0, start) 50 | ZEND_END_ARG_INFO() 51 | 52 | #define arginfo_class_BitSet_nextSetBit arginfo_class_BitSet_nextClearBit 53 | 54 | #define arginfo_class_BitSet_orOp arginfo_class_BitSet_andOp 55 | 56 | #define arginfo_class_BitSet_previousClearBit arginfo_class_BitSet_nextClearBit 57 | 58 | #define arginfo_class_BitSet_previousSetBit arginfo_class_BitSet_nextClearBit 59 | 60 | #define arginfo_class_BitSet_set arginfo_class_BitSet_clear 61 | 62 | #define arginfo_class_BitSet_size arginfo_class_BitSet_cardinality 63 | 64 | #define arginfo_class_BitSet_toArray arginfo_class_BitSet_cardinality 65 | 66 | #define arginfo_class_BitSet_toInteger arginfo_class_BitSet_cardinality 67 | 68 | #define arginfo_class_BitSet_xorOp arginfo_class_BitSet_andOp 69 | 70 | #define arginfo_class_BitSet___toString arginfo_class_BitSet_cardinality 71 | 72 | ZEND_METHOD(BitSet, __construct); 73 | ZEND_METHOD(BitSet, andOp); 74 | ZEND_METHOD(BitSet, andNotOp); 75 | ZEND_METHOD(BitSet, cardinality); 76 | ZEND_METHOD(BitSet, clear); 77 | ZEND_METHOD(BitSet, fromArray); 78 | ZEND_METHOD(BitSet, fromInteger); 79 | ZEND_METHOD(BitSet, fromString); 80 | ZEND_METHOD(BitSet, fromRawValue); 81 | ZEND_METHOD(BitSet, get); 82 | ZEND_METHOD(BitSet, getRawValue); 83 | ZEND_METHOD(BitSet, intersects); 84 | ZEND_METHOD(BitSet, isEmpty); 85 | ZEND_METHOD(BitSet, length); 86 | ZEND_METHOD(BitSet, nextClearBit); 87 | ZEND_METHOD(BitSet, nextSetBit); 88 | ZEND_METHOD(BitSet, orOp); 89 | ZEND_METHOD(BitSet, previousClearBit); 90 | ZEND_METHOD(BitSet, previousSetBit); 91 | ZEND_METHOD(BitSet, set); 92 | ZEND_METHOD(BitSet, size); 93 | ZEND_METHOD(BitSet, toArray); 94 | ZEND_METHOD(BitSet, toInteger); 95 | ZEND_METHOD(BitSet, xorOp); 96 | ZEND_METHOD(BitSet, __toString); 97 | 98 | static const zend_function_entry class_BitSet_methods[] = { 99 | ZEND_ME(BitSet, __construct, arginfo_class_BitSet___construct, ZEND_ACC_PUBLIC) 100 | ZEND_ME(BitSet, andOp, arginfo_class_BitSet_andOp, ZEND_ACC_PUBLIC) 101 | ZEND_ME(BitSet, andNotOp, arginfo_class_BitSet_andNotOp, ZEND_ACC_PUBLIC) 102 | ZEND_ME(BitSet, cardinality, arginfo_class_BitSet_cardinality, ZEND_ACC_PUBLIC) 103 | ZEND_ME(BitSet, clear, arginfo_class_BitSet_clear, ZEND_ACC_PUBLIC) 104 | ZEND_ME(BitSet, fromArray, arginfo_class_BitSet_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 105 | ZEND_ME(BitSet, fromInteger, arginfo_class_BitSet_fromInteger, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 106 | ZEND_ME(BitSet, fromString, arginfo_class_BitSet_fromString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 107 | ZEND_ME(BitSet, fromRawValue, arginfo_class_BitSet_fromRawValue, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 108 | ZEND_ME(BitSet, get, arginfo_class_BitSet_get, ZEND_ACC_PUBLIC) 109 | ZEND_ME(BitSet, getRawValue, arginfo_class_BitSet_getRawValue, ZEND_ACC_PUBLIC) 110 | ZEND_ME(BitSet, intersects, arginfo_class_BitSet_intersects, ZEND_ACC_PUBLIC) 111 | ZEND_ME(BitSet, isEmpty, arginfo_class_BitSet_isEmpty, ZEND_ACC_PUBLIC) 112 | ZEND_ME(BitSet, length, arginfo_class_BitSet_length, ZEND_ACC_PUBLIC) 113 | ZEND_ME(BitSet, nextClearBit, arginfo_class_BitSet_nextClearBit, ZEND_ACC_PUBLIC) 114 | ZEND_ME(BitSet, nextSetBit, arginfo_class_BitSet_nextSetBit, ZEND_ACC_PUBLIC) 115 | ZEND_ME(BitSet, orOp, arginfo_class_BitSet_orOp, ZEND_ACC_PUBLIC) 116 | ZEND_ME(BitSet, previousClearBit, arginfo_class_BitSet_previousClearBit, ZEND_ACC_PUBLIC) 117 | ZEND_ME(BitSet, previousSetBit, arginfo_class_BitSet_previousSetBit, ZEND_ACC_PUBLIC) 118 | ZEND_ME(BitSet, set, arginfo_class_BitSet_set, ZEND_ACC_PUBLIC) 119 | ZEND_ME(BitSet, size, arginfo_class_BitSet_size, ZEND_ACC_PUBLIC) 120 | ZEND_ME(BitSet, toArray, arginfo_class_BitSet_toArray, ZEND_ACC_PUBLIC) 121 | ZEND_ME(BitSet, toInteger, arginfo_class_BitSet_toInteger, ZEND_ACC_PUBLIC) 122 | ZEND_ME(BitSet, xorOp, arginfo_class_BitSet_xorOp, ZEND_ACC_PUBLIC) 123 | ZEND_ME(BitSet, __toString, arginfo_class_BitSet___toString, ZEND_ACC_PUBLIC) 124 | ZEND_FE_END 125 | }; 126 | 127 | static zend_class_entry *register_class_BitSet(void) 128 | { 129 | zend_class_entry ce, *class_entry; 130 | 131 | INIT_CLASS_ENTRY(ce, "BitSet", class_BitSet_methods); 132 | #if (PHP_VERSION_ID >= 80400) 133 | class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); 134 | #else 135 | class_entry = zend_register_internal_class_ex(&ce, NULL); 136 | #endif 137 | 138 | return class_entry; 139 | } 140 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | bitset 4 | pecl.php.net 5 | BITSET extension 6 | 7 | The BitSet extension assists by providing a mechanism to manage sets of bits. 8 | This provides a similar API (object-based) to java.util.BitSet with some PHP-specific flavoring. 9 | 10 | 11 | Will Fitch 12 | willfitch 13 | willfitch@php.net 14 | yes 15 | 16 | 17 | Remi Collet 18 | remi 19 | remi@php.net 20 | yes 21 | 22 | 2023-05-26 23 | 24 | 3.2.1dev 25 | 3.2.0 26 | 27 | 28 | stable 29 | stable 30 | 31 | PHP-3.01 32 | 33 | - 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 7.0.0 81 | 82 | 83 | 1.10.0 84 | 85 | 86 | 87 | bitset 88 | 89 | 90 | 91 | 2023-05-26 92 | 93 | 3.2.0 94 | 3.2.0 95 | 96 | 97 | stable 98 | stable 99 | 100 | PHP-3.01 101 | 102 | - fix BitSet::fromArray() to allow setting bit 0 103 | - add BitSet::fromInteger() and BitSet::toInteger() 104 | 105 | 106 | 107 | 2023-05-25 108 | 109 | 3.1.0 110 | 3.1.0 111 | 112 | 113 | stable 114 | stable 115 | 116 | PHP-3.01 117 | 118 | - add support for PHP 8.2 119 | - fix #63315: BitSet::fromArray may modify original array value (cmb) 120 | - add type hinting 121 | - minor optimizations 122 | 123 | 124 | 125 | 2017-10-05 126 | 127 | 3.0.1 128 | 3.0.1 129 | 130 | 131 | stable 132 | stable 133 | 134 | PHP-3.01 135 | 136 | - Fixed out of bounds bug (thanks kgodet) 137 | 138 | 139 | 140 | 141 | 1.0.1 142 | 1.0 143 | 144 | 145 | stable 146 | stable 147 | 148 | 2012-06-13 149 | PHP 150 | 151 | - Fixed build in PHP 5.3+ 152 | 153 | 154 | 155 | 156 | 1.0 157 | 1.0 158 | 159 | 160 | stable 161 | stable 162 | 163 | 2005-07-22 164 | PHP 165 | 166 | First official stable release of Bitset 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /bitset_arginfo.h: -------------------------------------------------------------------------------- 1 | /* This is a generated file, edit the .stub.php file instead. 2 | * Stub hash: 8da3818a0101d81ea3e553f6c3afbe1773ce2c55 */ 3 | 4 | ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BitSet___construct, 0, 0, 0) 5 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_LONG, 0, "0") 6 | ZEND_END_ARG_INFO() 7 | 8 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_andOp, 0, 1, IS_VOID, 0) 9 | ZEND_ARG_OBJ_INFO(0, set, BitSet, 0) 10 | ZEND_END_ARG_INFO() 11 | 12 | #define arginfo_class_BitSet_andNotOp arginfo_class_BitSet_andOp 13 | 14 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_cardinality, 0, 0, IS_LONG, 0) 15 | ZEND_END_ARG_INFO() 16 | 17 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_clear, 0, 0, IS_VOID, 0) 18 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, from, IS_LONG, 0, "-1") 19 | ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, to, IS_LONG, 0, "0") 20 | ZEND_END_ARG_INFO() 21 | 22 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BitSet_fromArray, 0, 1, BitSet, 0) 23 | ZEND_ARG_TYPE_INFO(0, arr, IS_ARRAY, 0) 24 | ZEND_END_ARG_INFO() 25 | 26 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BitSet_fromInteger, 0, 1, BitSet, 0) 27 | ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0) 28 | ZEND_END_ARG_INFO() 29 | 30 | ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BitSet_fromString, 0, 1, BitSet, 0) 31 | ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) 32 | ZEND_END_ARG_INFO() 33 | 34 | #define arginfo_class_BitSet_fromRawValue arginfo_class_BitSet_fromString 35 | 36 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_get, 0, 1, _IS_BOOL, 0) 37 | ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) 38 | ZEND_END_ARG_INFO() 39 | 40 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_getRawValue, 0, 0, IS_STRING, 0) 41 | ZEND_END_ARG_INFO() 42 | 43 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_intersects, 0, 1, _IS_BOOL, 0) 44 | ZEND_ARG_OBJ_INFO(0, set, BitSet, 0) 45 | ZEND_END_ARG_INFO() 46 | 47 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_isEmpty, 0, 0, _IS_BOOL, 0) 48 | ZEND_END_ARG_INFO() 49 | 50 | #define arginfo_class_BitSet_length arginfo_class_BitSet_cardinality 51 | 52 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_BitSet_nextClearBit, 0, 1, MAY_BE_BOOL|MAY_BE_LONG) 53 | ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0) 54 | ZEND_END_ARG_INFO() 55 | 56 | #define arginfo_class_BitSet_nextSetBit arginfo_class_BitSet_nextClearBit 57 | 58 | #define arginfo_class_BitSet_orOp arginfo_class_BitSet_andOp 59 | 60 | #define arginfo_class_BitSet_previousClearBit arginfo_class_BitSet_nextClearBit 61 | 62 | #define arginfo_class_BitSet_previousSetBit arginfo_class_BitSet_nextClearBit 63 | 64 | #define arginfo_class_BitSet_set arginfo_class_BitSet_clear 65 | 66 | #define arginfo_class_BitSet_size arginfo_class_BitSet_cardinality 67 | 68 | ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BitSet_toArray, 0, 0, IS_ARRAY, 0) 69 | ZEND_END_ARG_INFO() 70 | 71 | #define arginfo_class_BitSet_toInteger arginfo_class_BitSet_cardinality 72 | 73 | #define arginfo_class_BitSet_xorOp arginfo_class_BitSet_andOp 74 | 75 | #define arginfo_class_BitSet___toString arginfo_class_BitSet_getRawValue 76 | 77 | ZEND_METHOD(BitSet, __construct); 78 | ZEND_METHOD(BitSet, andOp); 79 | ZEND_METHOD(BitSet, andNotOp); 80 | ZEND_METHOD(BitSet, cardinality); 81 | ZEND_METHOD(BitSet, clear); 82 | ZEND_METHOD(BitSet, fromArray); 83 | ZEND_METHOD(BitSet, fromInteger); 84 | ZEND_METHOD(BitSet, fromString); 85 | ZEND_METHOD(BitSet, fromRawValue); 86 | ZEND_METHOD(BitSet, get); 87 | ZEND_METHOD(BitSet, getRawValue); 88 | ZEND_METHOD(BitSet, intersects); 89 | ZEND_METHOD(BitSet, isEmpty); 90 | ZEND_METHOD(BitSet, length); 91 | ZEND_METHOD(BitSet, nextClearBit); 92 | ZEND_METHOD(BitSet, nextSetBit); 93 | ZEND_METHOD(BitSet, orOp); 94 | ZEND_METHOD(BitSet, previousClearBit); 95 | ZEND_METHOD(BitSet, previousSetBit); 96 | ZEND_METHOD(BitSet, set); 97 | ZEND_METHOD(BitSet, size); 98 | ZEND_METHOD(BitSet, toArray); 99 | ZEND_METHOD(BitSet, toInteger); 100 | ZEND_METHOD(BitSet, xorOp); 101 | ZEND_METHOD(BitSet, __toString); 102 | 103 | static const zend_function_entry class_BitSet_methods[] = { 104 | ZEND_ME(BitSet, __construct, arginfo_class_BitSet___construct, ZEND_ACC_PUBLIC) 105 | ZEND_ME(BitSet, andOp, arginfo_class_BitSet_andOp, ZEND_ACC_PUBLIC) 106 | ZEND_ME(BitSet, andNotOp, arginfo_class_BitSet_andNotOp, ZEND_ACC_PUBLIC) 107 | ZEND_ME(BitSet, cardinality, arginfo_class_BitSet_cardinality, ZEND_ACC_PUBLIC) 108 | ZEND_ME(BitSet, clear, arginfo_class_BitSet_clear, ZEND_ACC_PUBLIC) 109 | ZEND_ME(BitSet, fromArray, arginfo_class_BitSet_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 110 | ZEND_ME(BitSet, fromInteger, arginfo_class_BitSet_fromInteger, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 111 | ZEND_ME(BitSet, fromString, arginfo_class_BitSet_fromString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 112 | ZEND_ME(BitSet, fromRawValue, arginfo_class_BitSet_fromRawValue, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 113 | ZEND_ME(BitSet, get, arginfo_class_BitSet_get, ZEND_ACC_PUBLIC) 114 | ZEND_ME(BitSet, getRawValue, arginfo_class_BitSet_getRawValue, ZEND_ACC_PUBLIC) 115 | ZEND_ME(BitSet, intersects, arginfo_class_BitSet_intersects, ZEND_ACC_PUBLIC) 116 | ZEND_ME(BitSet, isEmpty, arginfo_class_BitSet_isEmpty, ZEND_ACC_PUBLIC) 117 | ZEND_ME(BitSet, length, arginfo_class_BitSet_length, ZEND_ACC_PUBLIC) 118 | ZEND_ME(BitSet, nextClearBit, arginfo_class_BitSet_nextClearBit, ZEND_ACC_PUBLIC) 119 | ZEND_ME(BitSet, nextSetBit, arginfo_class_BitSet_nextSetBit, ZEND_ACC_PUBLIC) 120 | ZEND_ME(BitSet, orOp, arginfo_class_BitSet_orOp, ZEND_ACC_PUBLIC) 121 | ZEND_ME(BitSet, previousClearBit, arginfo_class_BitSet_previousClearBit, ZEND_ACC_PUBLIC) 122 | ZEND_ME(BitSet, previousSetBit, arginfo_class_BitSet_previousSetBit, ZEND_ACC_PUBLIC) 123 | ZEND_ME(BitSet, set, arginfo_class_BitSet_set, ZEND_ACC_PUBLIC) 124 | ZEND_ME(BitSet, size, arginfo_class_BitSet_size, ZEND_ACC_PUBLIC) 125 | ZEND_ME(BitSet, toArray, arginfo_class_BitSet_toArray, ZEND_ACC_PUBLIC) 126 | ZEND_ME(BitSet, toInteger, arginfo_class_BitSet_toInteger, ZEND_ACC_PUBLIC) 127 | ZEND_ME(BitSet, xorOp, arginfo_class_BitSet_xorOp, ZEND_ACC_PUBLIC) 128 | ZEND_ME(BitSet, __toString, arginfo_class_BitSet___toString, ZEND_ACC_PUBLIC) 129 | ZEND_FE_END 130 | }; 131 | 132 | static zend_class_entry *register_class_BitSet(void) 133 | { 134 | zend_class_entry ce, *class_entry; 135 | 136 | INIT_CLASS_ENTRY(ce, "BitSet", class_BitSet_methods); 137 | #if (PHP_VERSION_ID >= 80400) 138 | class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); 139 | #else 140 | class_entry = zend_register_internal_class_ex(&ce, NULL); 141 | #endif 142 | 143 | return class_entry; 144 | } 145 | -------------------------------------------------------------------------------- /bitset.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | http://www.php.net/license/3_01.txt. | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Authors: Will Fitch | 14 | | Alexander Veremyev | 15 | | Remi Collet | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "php.h" 24 | #include "php_ini.h" 25 | #include "zend_exceptions.h" 26 | #include "ext/spl/spl_exceptions.h" 27 | #include "ext/standard/info.h" 28 | #include "php_bitset.h" 29 | #include 30 | 31 | #if PHP_VERSION_ID >= 80000 32 | #include "bitset_arginfo.h" 33 | #else 34 | #include "bitset_legacy_arginfo.h" 35 | #define RETURN_THROWS() return 36 | #endif 37 | 38 | #define BITSET_DEPRECATED_MESSAGE "The bitset_* functions are deprecated and will be removed in 3.0. Please update to the BitSet class API" 39 | 40 | zend_class_entry *bitset_class_entry = NULL; 41 | static zend_object_handlers bitset_object_handlers; 42 | 43 | static php_bitset_object *bitset_get_intern_object(zval *object); 44 | static php_bitset_object *php_bitset_object_new(zend_class_entry *ce); 45 | static long bitset_get_highest_value_from_array(zval *arr); 46 | static void bitset_initialize_object(php_bitset_object *intern, long bits); 47 | 48 | 49 | /* {{{ zend_module_dep zend_module_entry ZEND_GET_MODULE 50 | */ 51 | 52 | zend_module_entry bitset_module_entry = { 53 | STANDARD_MODULE_HEADER_EX, NULL, 54 | NULL, 55 | "bitset", 56 | NULL, 57 | PHP_MINIT(bitset), 58 | PHP_MSHUTDOWN(bitset), 59 | NULL, 60 | NULL, 61 | PHP_MINFO(bitset), 62 | PHP_BITSET_VERSION, 63 | STANDARD_MODULE_PROPERTIES 64 | }; 65 | 66 | #ifdef COMPILE_DL_BITSET 67 | ZEND_GET_MODULE(bitset) 68 | #endif 69 | /* }}} */ 70 | 71 | /* {{{ proto void BitSet::__construct(int value) 72 | Class constructor */ 73 | PHP_METHOD(BitSet, __construct) 74 | { 75 | php_bitset_object *intern = NULL; 76 | zend_long bits = 0; 77 | 78 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &bits) == FAILURE) { 79 | RETURN_THROWS(); 80 | } 81 | 82 | intern = bitset_get_intern_object(getThis()); 83 | 84 | /* Default the bit count to 64 bits */ 85 | if (bits == 0) { 86 | bits = BITSET_DEFAULT_BITS; 87 | } else if (bits < 0) { 88 | /* Bits can't be negative */ 89 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 90 | "The total bits to allocate must be 0 or greater"); 91 | RETURN_THROWS(); 92 | } 93 | 94 | bitset_initialize_object(intern, bits); 95 | 96 | if (bits % CHAR_BIT) { 97 | intern->bitset_val[intern->bitset_len - 1] >>= (CHAR_BIT - (bits % CHAR_BIT)); 98 | } 99 | } 100 | /* }}} */ 101 | 102 | /* {{{ proto void BitSet::andOp(BitSet set) 103 | Performs a logical AND of target bit set with provided object */ 104 | PHP_METHOD(BitSet, andOp) 105 | { 106 | php_bitset_object *intern, *param; 107 | zval *param_id; 108 | long bitset_len1, bitset_len2, i, to_bits; 109 | 110 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", ¶m_id, bitset_class_entry) == FAILURE) { 111 | RETURN_THROWS(); 112 | } 113 | 114 | intern = bitset_get_intern_object(getThis()); 115 | param = bitset_get_intern_object(param_id); 116 | bitset_len1 = intern->bitset_len; 117 | bitset_len2 = param->bitset_len; 118 | to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1; 119 | 120 | for (i = 0; i < to_bits; i++) { 121 | intern->bitset_val[i] &= param->bitset_val[i]; 122 | } 123 | } 124 | /* }}} */ 125 | 126 | /* {{{ proto void BitSet::andNotOp(BitSet set) 127 | Clears all bits in this object whose bit is set in the provided object */ 128 | PHP_METHOD(BitSet, andNotOp) 129 | { 130 | php_bitset_object *intern, *param; 131 | zval *param_id; 132 | long bitset_len1, bitset_len2, i, to_bits; 133 | 134 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", ¶m_id, bitset_class_entry) == FAILURE) { 135 | RETURN_THROWS(); 136 | } 137 | 138 | intern = bitset_get_intern_object(getThis()); 139 | param = bitset_get_intern_object(param_id); 140 | bitset_len1 = intern->bitset_len * CHAR_BIT; 141 | bitset_len2 = param->bitset_len * CHAR_BIT; 142 | to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1; 143 | 144 | for (i = 0; i < to_bits; i++) { 145 | /* If the incoming bit is set, clear on this object */ 146 | if (param->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) { 147 | intern->bitset_val[i / CHAR_BIT] &= ~(1 << (i % CHAR_BIT)); 148 | } 149 | } 150 | } 151 | /* }}} */ 152 | 153 | /* {{{ proto int BitSet::cardinality(void) 154 | Returns the number of true bits */ 155 | PHP_METHOD(BitSet, cardinality) 156 | { 157 | php_bitset_object *intern; 158 | long i, total_bits, true_bits = 0; 159 | 160 | if (zend_parse_parameters_none() == FAILURE) { 161 | RETURN_THROWS(); 162 | } 163 | 164 | intern = bitset_get_intern_object(getThis()); 165 | 166 | total_bits = intern->bitset_len * CHAR_BIT; 167 | 168 | for (i = 0; i < total_bits; i++) { 169 | if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) { 170 | true_bits++; 171 | } 172 | } 173 | 174 | RETURN_LONG(true_bits); 175 | } 176 | /* }}} */ 177 | 178 | /* {{{ proto void BitSet::clear([int indexOrFromIndex[, int toIndex]]) 179 | Sets all bits to false */ 180 | PHP_METHOD(BitSet, clear) 181 | { 182 | php_bitset_object *intern; 183 | long index_from = -1, index_to = 0, usable_index = 0; 184 | 185 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &index_from, &index_to) == FAILURE) { 186 | RETURN_THROWS(); 187 | } 188 | 189 | intern = bitset_get_intern_object(getThis()); 190 | 191 | /* Clear all bits and reset */ 192 | if (index_from == -1 && index_to == 0) { 193 | memset(intern->bitset_val, 0, intern->bitset_len); 194 | intern->bitset_val[intern->bitset_len] = '\0'; 195 | } else { 196 | /* Verify the start index is not greater than total bits */ 197 | if (index_from >= intern->bitset_len * CHAR_BIT) { 198 | zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, 199 | "The requested start index is greater than the total number of bits"); 200 | RETURN_THROWS(); 201 | } 202 | 203 | if (index_to == 0) { 204 | usable_index = index_from; 205 | } else { 206 | usable_index = index_to > intern->bitset_len * CHAR_BIT ? intern->bitset_len * CHAR_BIT : index_to; 207 | } 208 | 209 | for (; index_from <= usable_index; index_from++) { 210 | intern->bitset_val[index_from / CHAR_BIT] &= ~(1 << (index_from % CHAR_BIT)); 211 | } 212 | } 213 | } 214 | /* }}} */ 215 | 216 | /* {{{ proto bool BitSet::get(int index) 217 | Returns the bool value of the bit at the specified index */ 218 | PHP_METHOD(BitSet, get) 219 | { 220 | php_bitset_object *intern; 221 | zend_long bit; 222 | 223 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bit) == FAILURE) { 224 | RETURN_THROWS(); 225 | } 226 | 227 | intern = bitset_get_intern_object(getThis()); 228 | 229 | /* The bit requested is larger than all bits in this set */ 230 | if (bit >= intern->bitset_len * CHAR_BIT) { 231 | zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, 232 | "The specified index parameter exceeds the total number of bits available"); 233 | RETURN_THROWS(); 234 | } 235 | 236 | if (intern->bitset_val[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT))) { 237 | RETURN_TRUE; 238 | } else { 239 | RETURN_FALSE; 240 | } 241 | } 242 | /* }}} */ 243 | 244 | /* {{{ proto string BitSet::getRawValue(void) 245 | */ 246 | PHP_METHOD(BitSet, getRawValue) 247 | { 248 | php_bitset_object *intern; 249 | intern = bitset_get_intern_object(getThis()); 250 | 251 | if (zend_parse_parameters_none() == FAILURE) { 252 | RETURN_THROWS(); 253 | } 254 | 255 | if (intern->bitset_val) { 256 | RETURN_STRINGL((char *) intern->bitset_val, intern->bitset_len); 257 | } else { 258 | RETURN_EMPTY_STRING(); 259 | } 260 | } 261 | /* }}} */ 262 | 263 | /* {{{ proto string BitSet::fromRawValue(void) 264 | */ 265 | PHP_METHOD(BitSet, fromRawValue) 266 | { 267 | php_bitset_object *newobj; 268 | zend_class_entry *ce = bitset_class_entry; 269 | zend_string *str; 270 | 271 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) { 272 | RETURN_THROWS(); 273 | } 274 | 275 | newobj = php_bitset_object_new(ce); 276 | 277 | if (str->len == 0) { 278 | bitset_initialize_object(newobj, BITSET_DEFAULT_BITS); 279 | return; 280 | } 281 | 282 | bitset_initialize_object(newobj, (str->len * CHAR_BIT)); 283 | memcpy(newobj->bitset_val, str->val, str->len); 284 | 285 | ZVAL_OBJ(return_value, &newobj->zo); 286 | } 287 | /* }}} */ 288 | 289 | /* {{{ proto bool BitSet::intersects(BitSet set) 290 | Determines if the provided value has any bits set to true that are also true in this object */ 291 | PHP_METHOD(BitSet, intersects) 292 | { 293 | php_bitset_object *a, *b; 294 | zval *param_id; 295 | long bitset_len1, bitset_len2, i, to_bits; 296 | 297 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", ¶m_id, bitset_class_entry) == FAILURE) { 298 | RETURN_THROWS(); 299 | } 300 | 301 | a = bitset_get_intern_object(getThis()); 302 | b = bitset_get_intern_object(param_id); 303 | bitset_len1 = a->bitset_len; 304 | bitset_len2 = b->bitset_len; 305 | 306 | to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1; 307 | 308 | for (i = 0; i < to_bits; i++) { 309 | /* If the bits is set in both */ 310 | if (a->bitset_val[i] & b->bitset_val[i]) { 311 | RETURN_TRUE; 312 | } 313 | } 314 | RETURN_FALSE; 315 | } 316 | /* }}} */ 317 | 318 | /* {{{ proto bool BitSet::isEmpty(void) 319 | Determines if this value contains no bits */ 320 | PHP_METHOD(BitSet, isEmpty) 321 | { 322 | php_bitset_object *intern; 323 | long total_bits, i; 324 | 325 | if (zend_parse_parameters_none() == FAILURE) { 326 | RETURN_THROWS(); 327 | } 328 | 329 | intern = bitset_get_intern_object(getThis()); 330 | total_bits = intern->bitset_len; 331 | 332 | /* Loop through all bits and determine if there is a true bit. */ 333 | for (i = 0; i < total_bits; i++) { 334 | if (intern->bitset_val[i]) { 335 | RETURN_FALSE; 336 | } 337 | } 338 | 339 | RETURN_TRUE; 340 | } 341 | /* }}} */ 342 | 343 | /* {{{ proto int BitSet::length(void) 344 | Returns the highest set bit plus one 345 | */ 346 | PHP_METHOD(BitSet, length) 347 | { 348 | php_bitset_object *intern; 349 | long highest_bit = -1, i; 350 | 351 | if (zend_parse_parameters_none() == FAILURE) { 352 | RETURN_THROWS(); 353 | } 354 | 355 | intern = bitset_get_intern_object(getThis()); 356 | i = intern->bitset_len * CHAR_BIT; 357 | 358 | while (i > 0) { 359 | i--; 360 | 361 | if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) { 362 | highest_bit = i; 363 | break; 364 | } 365 | } 366 | 367 | RETURN_LONG(highest_bit + 1); 368 | } 369 | /* }}} */ 370 | 371 | /* {{{ proto int BitSet::nextClearBit(int index) 372 | Returns the index of the next bit after the provided index that is set to false */ 373 | PHP_METHOD(BitSet, nextClearBit) 374 | { 375 | php_bitset_object *intern; 376 | zend_long start_bit = 0; 377 | long bit_diff = 0, next_bit = 0; 378 | short found = 0; 379 | 380 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) { 381 | RETURN_THROWS(); 382 | } 383 | 384 | intern = bitset_get_intern_object(getThis()); 385 | bit_diff = intern->bitset_len * CHAR_BIT; 386 | 387 | if (start_bit >= bit_diff - 1) { 388 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 389 | "There are no bits larger than the index provided"); 390 | RETURN_THROWS(); 391 | } 392 | 393 | start_bit++; 394 | 395 | while (start_bit <= bit_diff) { 396 | if (!(intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT)))) { 397 | next_bit = start_bit; 398 | found = 1; 399 | break; 400 | } 401 | 402 | start_bit++; 403 | } 404 | 405 | if (found) { 406 | RETURN_LONG(next_bit); 407 | } else { 408 | RETURN_FALSE; 409 | } 410 | } 411 | /* }}} */ 412 | 413 | /* {{{ proto int BitSet::nextSetBit(int index) 414 | Returns the index of the next bit after the provided index that is set to true */ 415 | PHP_METHOD(BitSet, nextSetBit) 416 | { 417 | php_bitset_object *intern; 418 | zend_long start_bit = 0; 419 | long bit_diff = 0, next_bit = 0; 420 | short found = 0; 421 | 422 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) { 423 | RETURN_THROWS(); 424 | } 425 | 426 | intern = bitset_get_intern_object(getThis()); 427 | bit_diff = intern->bitset_len * CHAR_BIT; 428 | 429 | if (start_bit >= bit_diff - 1) { 430 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 431 | "There are no bits larger than the index provided"); 432 | RETURN_THROWS(); 433 | } 434 | 435 | start_bit++; 436 | 437 | while (start_bit <= bit_diff) { 438 | if (intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT))) { 439 | next_bit = start_bit; 440 | found = 1; 441 | break; 442 | } 443 | 444 | start_bit++; 445 | } 446 | 447 | if (found) { 448 | RETURN_LONG(next_bit); 449 | } else { 450 | RETURN_FALSE; 451 | } 452 | } 453 | /* }}} */ 454 | 455 | /* {{{ proto void BitSet::orOp(BitSet set) 456 | Performs a logical OR of this object with the provided argument object */ 457 | PHP_METHOD(BitSet, orOp) 458 | { 459 | php_bitset_object *intern, *param; 460 | zval *param_id; 461 | long bitset_len1, bitset_len2, i, to_bits; 462 | 463 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", ¶m_id, bitset_class_entry) == FAILURE) { 464 | RETURN_THROWS(); 465 | } 466 | 467 | intern = bitset_get_intern_object(getThis()); 468 | param = bitset_get_intern_object(param_id); 469 | bitset_len1 = intern->bitset_len; 470 | bitset_len2 = param->bitset_len; 471 | to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1; 472 | 473 | for (i = 0; i < to_bits; i++) { 474 | intern->bitset_val[i] |= param->bitset_val[i]; 475 | } 476 | } 477 | /* }}} */ 478 | 479 | /* {{{ proto int BitSet::previousClearBit(int index) 480 | Returns the index of the previous bit before the provided index that is set to false */ 481 | PHP_METHOD(BitSet, previousClearBit) 482 | { 483 | php_bitset_object *intern; 484 | long start_bit = 0, bit_diff = 0; 485 | 486 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) { 487 | RETURN_THROWS(); 488 | } 489 | 490 | if (start_bit < 1) { 491 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 492 | "There are no bits smaller than the index provided"); 493 | RETURN_THROWS(); 494 | } 495 | 496 | intern = bitset_get_intern_object(getThis()); 497 | bit_diff = intern->bitset_len * CHAR_BIT; 498 | 499 | if (start_bit > bit_diff) { 500 | zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, 501 | "The specified index parameter exceeds the total number of bits available"); 502 | RETURN_THROWS(); 503 | } 504 | 505 | start_bit--; 506 | 507 | while (start_bit >= 0) { 508 | if (!(intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT)))) { 509 | break; 510 | } 511 | 512 | start_bit--; 513 | } 514 | 515 | if (start_bit < 0) { 516 | RETURN_FALSE; 517 | } else { 518 | RETURN_LONG(start_bit); 519 | } 520 | } 521 | /* }}} */ 522 | 523 | /* {{{ proto int BitSet::previousSetBit(int index) 524 | Returns the index of the previous bit before the provided index that is set to true */ 525 | PHP_METHOD(BitSet, previousSetBit) 526 | { 527 | php_bitset_object *intern; 528 | zend_long start_bit = 0; 529 | long bit_diff = 0; 530 | 531 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) { 532 | RETURN_THROWS(); 533 | } 534 | 535 | if (start_bit < 1) { 536 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 537 | "There are no bits smaller than the index provided"); 538 | RETURN_THROWS(); 539 | } 540 | 541 | intern = bitset_get_intern_object(getThis()); 542 | bit_diff = intern->bitset_len * CHAR_BIT; 543 | 544 | if (start_bit > bit_diff) { 545 | zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, 546 | "The specified index parameter exceeds the total number of bits available"); 547 | RETURN_THROWS(); 548 | } 549 | 550 | start_bit--; 551 | 552 | while (start_bit >= 0) { 553 | if (intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT))) { 554 | break; 555 | } 556 | 557 | start_bit--; 558 | } 559 | 560 | if (start_bit < 0) { 561 | RETURN_FALSE; 562 | } else { 563 | RETURN_LONG(start_bit); 564 | } 565 | } 566 | /* }}} */ 567 | 568 | /* {{{ proto void BitSet::set([int indexOrFromIndex[, toIndex]]) 569 | Sets the bits from the specified index or range to true 570 | */ 571 | PHP_METHOD(BitSet, set) 572 | { 573 | php_bitset_object *intern; 574 | zend_long index_from = -1, index_to = 0; 575 | long usable_index = 0; 576 | 577 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &index_from, &index_to) == FAILURE) { 578 | RETURN_THROWS(); 579 | } 580 | 581 | intern = bitset_get_intern_object(getThis()); 582 | 583 | /* Set all bits */ 584 | if (index_from == -1 && index_to == 0) { 585 | for (; usable_index < intern->bitset_len * CHAR_BIT; usable_index++) 586 | { 587 | intern->bitset_val[usable_index / CHAR_BIT] |= (1 << (usable_index % CHAR_BIT)); 588 | } 589 | 590 | intern->bitset_val[intern->bitset_len] = '\0'; 591 | } else { 592 | /* Verify the start index is not greater than total bits */ 593 | if (index_from > (intern->bitset_len * CHAR_BIT - 1)) { 594 | zend_throw_exception_ex(spl_ce_OutOfRangeException, 0, 595 | "The requested start index is greater than the total number of bits"); 596 | RETURN_THROWS(); 597 | } 598 | 599 | if (index_to == 0) { 600 | usable_index = index_from; 601 | } else { 602 | usable_index = index_to > intern->bitset_len * CHAR_BIT ? intern->bitset_len * CHAR_BIT : index_to; 603 | } 604 | 605 | for (; index_from <= usable_index; index_from++) { 606 | intern->bitset_val[index_from / CHAR_BIT] |= (1 << (index_from % CHAR_BIT)); 607 | } 608 | } 609 | } 610 | /* }}} */ 611 | 612 | /* {{{ proto int BitSet::size(void) 613 | Returns the number of bits of space in use */ 614 | PHP_METHOD(BitSet, size) 615 | { 616 | php_bitset_object *intern; 617 | intern = bitset_get_intern_object(getThis()); 618 | 619 | if (zend_parse_parameters_none() == FAILURE) { 620 | RETURN_THROWS(); 621 | } 622 | 623 | RETURN_LONG(intern->bitset_len * CHAR_BIT); 624 | } 625 | /* }}} */ 626 | 627 | /* {{{ proto BitSet BitSet::fromString(string) 628 | * Returns a new instance of BitSet based on the provided string 629 | */ 630 | PHP_METHOD(BitSet, fromString) 631 | { 632 | php_bitset_object *newobj; 633 | zend_class_entry *ce = bitset_class_entry; 634 | zend_string *str = NULL; 635 | int i; 636 | 637 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) { 638 | RETURN_THROWS(); 639 | } 640 | 641 | newobj = php_bitset_object_new(ce); 642 | 643 | if (str->len > 0) { 644 | bitset_initialize_object(newobj, str->len); 645 | } else { 646 | bitset_initialize_object(newobj, BITSET_DEFAULT_BITS); 647 | } 648 | 649 | for (i = 0; i < str->len; i++) { 650 | /* If the char is explicitly '1', set it as 1. Otherwise, it's 0 */ 651 | if (str->val[i] == '1') { 652 | newobj->bitset_val[i / CHAR_BIT] |= (1 << (i % CHAR_BIT)); 653 | } 654 | } 655 | 656 | ZVAL_OBJ(return_value, &newobj->zo); 657 | } 658 | /* }}} */ 659 | 660 | /* {{{ proto BitSet BitSet::fromArray(array inputArray) 661 | * Returns a new Bitset instance based on the input array. All positive integers 662 | * within the array values are considered positions of set bits 663 | */ 664 | PHP_METHOD(BitSet, fromArray) 665 | { 666 | php_bitset_object *newobj; 667 | zval *bit_array; 668 | zval *entry; 669 | zend_class_entry *ce = bitset_class_entry; 670 | long array_len, highest_value, entry_actual; 671 | 672 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &bit_array) == FAILURE) { 673 | RETURN_THROWS(); 674 | } 675 | 676 | array_len = zend_hash_num_elements(Z_ARRVAL_P(bit_array)); 677 | newobj = php_bitset_object_new(ce); 678 | 679 | if (array_len == 0) { 680 | bitset_initialize_object(newobj, BITSET_DEFAULT_BITS); 681 | return; 682 | } 683 | 684 | highest_value = bitset_get_highest_value_from_array(bit_array); 685 | bitset_initialize_object(newobj, highest_value+1); 686 | 687 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(bit_array), entry) { 688 | zend_long entry_long = zval_get_long(entry); 689 | 690 | if (entry_long >= 0) { 691 | entry_actual = entry_long / CHAR_BIT; 692 | newobj->bitset_val[entry_actual] |= (1 << (entry_long % CHAR_BIT)); 693 | } 694 | } ZEND_HASH_FOREACH_END(); 695 | 696 | ZVAL_OBJ(return_value, &newobj->zo); 697 | } 698 | /* }}} */ 699 | 700 | /* {{{ proto array BitSet::toArray(void) 701 | Returns the on bits as an array */ 702 | PHP_METHOD(BitSet, toArray) 703 | { 704 | php_bitset_object *intern; 705 | long i, total_bits; 706 | 707 | if (zend_parse_parameters_none() == FAILURE) { 708 | RETURN_THROWS(); 709 | } 710 | 711 | intern = bitset_get_intern_object(getThis()); 712 | array_init(return_value); 713 | total_bits = intern->bitset_len * CHAR_BIT; 714 | 715 | for (i = 0; i < total_bits; i++) { 716 | if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) { 717 | add_next_index_long(return_value, i); 718 | } 719 | } 720 | } 721 | /* }}} */ 722 | 723 | /* {{{ proto BitSet BitSet::fromInteger(integer value) 724 | * Returns a new Bitset instance based on the input value 725 | */ 726 | PHP_METHOD(BitSet, fromInteger) 727 | { 728 | php_bitset_object *newobj; 729 | zend_class_entry *ce = bitset_class_entry; 730 | zend_long value; 731 | int i; 732 | 733 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) { 734 | RETURN_THROWS(); 735 | } 736 | 737 | newobj = php_bitset_object_new(ce); 738 | 739 | bitset_initialize_object(newobj, sizeof(value) * CHAR_BIT); 740 | 741 | for (i = 0; i < sizeof(value) ; i++) { 742 | newobj->bitset_val[i] = value & ((1 << CHAR_BIT) -1); 743 | value >>= CHAR_BIT; 744 | } 745 | 746 | ZVAL_OBJ(return_value, &newobj->zo); 747 | } 748 | /* }}} */ 749 | 750 | /* {{{ proto integer BitSet::toInteger(void) 751 | Returns the on bits as an integer */ 752 | PHP_METHOD(BitSet, toInteger) 753 | { 754 | php_bitset_object *intern; 755 | int i; 756 | zend_long value = 0; 757 | 758 | if (zend_parse_parameters_none() == FAILURE) { 759 | RETURN_THROWS(); 760 | } 761 | 762 | intern = bitset_get_intern_object(getThis()); 763 | if (intern->bitset_len > sizeof(value)) { 764 | zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, 765 | "The total bits doesn't fit in an integer"); 766 | RETURN_THROWS(); 767 | } 768 | 769 | for (i = 0; i < intern->bitset_len; i++) { 770 | value |= intern->bitset_val[i] << (i * CHAR_BIT); 771 | } 772 | RETURN_LONG(value); 773 | } 774 | /* }}} */ 775 | 776 | /* {{{ proto void BitSet::xorOp(BitSet set) 777 | Performs an XOR operation against the current object bit set with the specified argument */ 778 | PHP_METHOD(BitSet, xorOp) 779 | { 780 | php_bitset_object *intern, *param; 781 | zval *param_id; 782 | long bitset_len1, bitset_len2, i, to_bits; 783 | 784 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", ¶m_id, bitset_class_entry) == FAILURE) { 785 | RETURN_THROWS(); 786 | } 787 | 788 | intern = bitset_get_intern_object(getThis()); 789 | param = bitset_get_intern_object(param_id); 790 | bitset_len1 = intern->bitset_len; 791 | bitset_len2 = param->bitset_len; 792 | to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1; 793 | 794 | for (i = 0; i < to_bits; i++) { 795 | intern->bitset_val[i] ^= param->bitset_val[i]; 796 | } 797 | } 798 | /* }}} */ 799 | 800 | /* {{{ proto string BitSet::__toString(void) 801 | Returns a human-readable string representation of the bit set */ 802 | PHP_METHOD(BitSet, __toString) 803 | { 804 | php_bitset_object *intern = NULL; 805 | zend_string *retval; 806 | char *internval = NULL; 807 | long len, i; 808 | 809 | if (zend_parse_parameters_none() == FAILURE) { 810 | RETURN_THROWS(); 811 | } 812 | 813 | intern = bitset_get_intern_object(getThis()); 814 | 815 | if (intern->bitset_len == 0) { 816 | RETURN_EMPTY_STRING(); 817 | } else { 818 | len = intern->bitset_len * CHAR_BIT; 819 | retval = zend_string_alloc(len, 0); 820 | internval = ZSTR_VAL(retval); 821 | internval[len] = '\0'; 822 | 823 | for (i = 0; i < len; i++) { 824 | internval[i] = ((intern->bitset_val[i / CHAR_BIT] >> (i % CHAR_BIT)) & 1) ? '1' : '0'; 825 | } 826 | 827 | RETURN_STR(retval); 828 | } 829 | } 830 | /* }}} */ 831 | 832 | /* {{{ php_bitset_object *bitset_get_intern_object 833 | */ 834 | static php_bitset_object *bitset_get_intern_object(zval *object) 835 | { 836 | zend_object *obj = Z_OBJ_P(object); 837 | return php_bitset_fetch_object(obj); 838 | } 839 | /* }}} */ 840 | 841 | /* {{{ long bitset_get_highest_value_from_array 842 | */ 843 | static long bitset_get_highest_value_from_array(zval *arr) 844 | { 845 | zval *entry; 846 | long highest_value = 0; 847 | 848 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), entry) { 849 | zend_long entry_long = zval_get_long(entry); 850 | 851 | if (entry_long > highest_value) { 852 | highest_value = entry_long; 853 | } 854 | } ZEND_HASH_FOREACH_END(); 855 | 856 | return highest_value; 857 | } 858 | /* }}} */ 859 | 860 | /* {{{ php_bitset_object php_bitset_object_new 861 | */ 862 | static php_bitset_object *php_bitset_object_new(zend_class_entry *ce) 863 | { 864 | php_bitset_object *intern; 865 | intern = ecalloc(1, sizeof(php_bitset_object) + zend_object_properties_size(ce)); 866 | intern->bitset_val = 0; 867 | 868 | zend_object_std_init(&intern->zo, ce); 869 | object_properties_init(&intern->zo, ce); 870 | 871 | intern->zo.handlers = &bitset_object_handlers; 872 | return intern; 873 | } 874 | /* }}} */ 875 | 876 | /* {{{ void bitset_initialize_object 877 | */ 878 | static void bitset_initialize_object(php_bitset_object *intern, long bits) 879 | { 880 | intern->bitset_len = (bits + CHAR_BIT - 1) / CHAR_BIT; 881 | intern->bitset_val = (unsigned char *) emalloc(intern->bitset_len + 1); 882 | memset(intern->bitset_val, 0, intern->bitset_len); 883 | intern->bitset_val[intern->bitset_len] = '\0'; 884 | } 885 | /* }}} */ 886 | 887 | /* {{{ bitset_destroy_object 888 | */ 889 | static void bitset_destroy_object(zend_object *obj) 890 | { 891 | zend_objects_destroy_object(obj); 892 | } 893 | /* }}} */ 894 | 895 | /* {{{ void bitset_free_object 896 | */ 897 | static void bitset_free_object(zend_object *obj) 898 | { 899 | php_bitset_object *bitset_obj; 900 | bitset_obj = php_bitset_fetch_object(obj); 901 | 902 | if (bitset_obj->bitset_val) { 903 | efree(bitset_obj->bitset_val); 904 | } 905 | 906 | zend_object_std_dtor(obj); 907 | } 908 | /* }}} */ 909 | 910 | /* {{{ zend_object bitset_create_object 911 | */ 912 | static zend_object *bitset_create_object(zend_class_entry *ce) 913 | { 914 | php_bitset_object *intern; 915 | intern = ecalloc(1, sizeof(php_bitset_object) + zend_object_properties_size(ce)); 916 | intern->bitset_val = 0; 917 | 918 | zend_object_std_init(&intern->zo, ce); 919 | object_properties_init(&intern->zo, ce); 920 | 921 | intern->zo.handlers = &bitset_object_handlers; 922 | return &intern->zo; 923 | } 924 | /* }}} */ 925 | 926 | /* {{{ PHP_MINFO_FUNCTION */ 927 | PHP_MINFO_FUNCTION(bitset) 928 | { 929 | php_info_print_table_start(); 930 | php_info_print_table_header(2, "BitSet Support", "enabled"); 931 | php_info_print_table_row(2, "BitSet Version", PHP_BITSET_VERSION); 932 | php_info_print_table_row(2, "64-bit Integer Support", sizeof(unsigned long long) == 8 ? "yes" : "no"); 933 | php_info_print_table_end(); 934 | DISPLAY_INI_ENTRIES(); 935 | } 936 | /* }}} */ 937 | 938 | /* {{{ PHP_MINIT_FUNCTION */ 939 | PHP_MINIT_FUNCTION(bitset) 940 | { 941 | bitset_class_entry = register_class_BitSet(); 942 | 943 | bitset_class_entry->create_object = bitset_create_object; 944 | 945 | memcpy(&bitset_object_handlers, zend_get_std_object_handlers(), sizeof(bitset_object_handlers)); 946 | bitset_object_handlers.free_obj = bitset_free_object; 947 | bitset_object_handlers.dtor_obj = bitset_destroy_object; 948 | bitset_object_handlers.offset = XtOffsetOf(php_bitset_object, zo); 949 | 950 | return SUCCESS; 951 | } 952 | /* }}} */ 953 | 954 | /* {{{ PHP_MSHUTDOWN_FUNCTION */ 955 | PHP_MSHUTDOWN_FUNCTION(bitset) 956 | { 957 | bitset_class_entry = NULL; 958 | return SUCCESS; 959 | } 960 | /* }}} */ 961 | 962 | /* 963 | * Local variables: 964 | * tab-width: 4 965 | * c-basic-offset: 4 966 | * End: 967 | * vim600: noet sw=4 ts=4 fdm=marker 968 | * vim<600: noet sw=4 ts=4 969 | */ 970 | --------------------------------------------------------------------------------