Files
2023-05-26 15:54:12 +02:00

970 lines
24 KiB
C

/*
+----------------------------------------------------------------------+
| Copyright (c) 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: Will Fitch <willfitch@php.net> |
| Alexander Veremyev <cawa@csa.ru> |
| Remi Collet <remi@php.net> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "zend_exceptions.h"
#include "ext/spl/spl_exceptions.h"
#include "ext/standard/info.h"
#include "php_bitset.h"
#include <limits.h>
#if PHP_VERSION_ID >= 80000
#include "bitset_arginfo.h"
#else
#include "bitset_legacy_arginfo.h"
#define RETURN_THROWS() return
#endif
#define BITSET_DEPRECATED_MESSAGE "The bitset_* functions are deprecated and will be removed in 3.0. Please update to the BitSet class API"
zend_class_entry *bitset_class_entry = NULL;
static zend_object_handlers bitset_object_handlers;
static php_bitset_object *bitset_get_intern_object(zval *object);
static php_bitset_object *php_bitset_object_new(zend_class_entry *ce);
static long bitset_get_highest_value_from_array(zval *arr);
static void bitset_initialize_object(php_bitset_object *intern, long bits);
/* {{{ zend_module_dep zend_module_entry ZEND_GET_MODULE
*/
zend_module_entry bitset_module_entry = {
STANDARD_MODULE_HEADER_EX, NULL,
NULL,
"bitset",
NULL,
PHP_MINIT(bitset),
PHP_MSHUTDOWN(bitset),
NULL,
NULL,
PHP_MINFO(bitset),
PHP_BITSET_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_BITSET
ZEND_GET_MODULE(bitset)
#endif
/* }}} */
/* {{{ proto void BitSet::__construct(int value)
Class constructor */
PHP_METHOD(BitSet, __construct)
{
php_bitset_object *intern = NULL;
zend_long bits = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &bits) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
/* Default the bit count to 64 bits */
if (bits == 0) {
bits = BITSET_DEFAULT_BITS;
} else if (bits < 0) {
/* Bits can't be negative */
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"The total bits to allocate must be 0 or greater");
RETURN_THROWS();
}
bitset_initialize_object(intern, bits);
if (bits % CHAR_BIT) {
intern->bitset_val[intern->bitset_len - 1] >>= (CHAR_BIT - (bits % CHAR_BIT));
}
}
/* }}} */
/* {{{ proto void BitSet::andOp(BitSet set)
Performs a logical AND of target bit set with provided object */
PHP_METHOD(BitSet, andOp)
{
php_bitset_object *intern, *param;
zval *param_id;
long bitset_len1, bitset_len2, i, to_bits;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &param_id, bitset_class_entry) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
param = bitset_get_intern_object(param_id);
bitset_len1 = intern->bitset_len;
bitset_len2 = param->bitset_len;
to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1;
for (i = 0; i < to_bits; i++) {
intern->bitset_val[i] &= param->bitset_val[i];
}
}
/* }}} */
/* {{{ proto void BitSet::andNotOp(BitSet set)
Clears all bits in this object whose bit is set in the provided object */
PHP_METHOD(BitSet, andNotOp)
{
php_bitset_object *intern, *param;
zval *param_id;
long bitset_len1, bitset_len2, i, to_bits;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &param_id, bitset_class_entry) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
param = bitset_get_intern_object(param_id);
bitset_len1 = intern->bitset_len * CHAR_BIT;
bitset_len2 = param->bitset_len * CHAR_BIT;
to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1;
for (i = 0; i < to_bits; i++) {
/* If the incoming bit is set, clear on this object */
if (param->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) {
intern->bitset_val[i / CHAR_BIT] &= ~(1 << (i % CHAR_BIT));
}
}
}
/* }}} */
/* {{{ proto int BitSet::cardinality(void)
Returns the number of true bits */
PHP_METHOD(BitSet, cardinality)
{
php_bitset_object *intern;
long i, total_bits, true_bits = 0;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
total_bits = intern->bitset_len * CHAR_BIT;
for (i = 0; i < total_bits; i++) {
if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) {
true_bits++;
}
}
RETURN_LONG(true_bits);
}
/* }}} */
/* {{{ proto void BitSet::clear([int indexOrFromIndex[, int toIndex]])
Sets all bits to false */
PHP_METHOD(BitSet, clear)
{
php_bitset_object *intern;
long index_from = -1, index_to = 0, usable_index = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &index_from, &index_to) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
/* Clear all bits and reset */
if (index_from == -1 && index_to == 0) {
memset(intern->bitset_val, 0, intern->bitset_len);
intern->bitset_val[intern->bitset_len] = '\0';
} else {
/* Verify the start index is not greater than total bits */
if (index_from >= intern->bitset_len * CHAR_BIT) {
zend_throw_exception_ex(spl_ce_OutOfRangeException, 0,
"The requested start index is greater than the total number of bits");
RETURN_THROWS();
}
if (index_to == 0) {
usable_index = index_from;
} else {
usable_index = index_to > intern->bitset_len * CHAR_BIT ? intern->bitset_len * CHAR_BIT : index_to;
}
for (; index_from <= usable_index; index_from++) {
intern->bitset_val[index_from / CHAR_BIT] &= ~(1 << (index_from % CHAR_BIT));
}
}
}
/* }}} */
/* {{{ proto bool BitSet::get(int index)
Returns the bool value of the bit at the specified index */
PHP_METHOD(BitSet, get)
{
php_bitset_object *intern;
zend_long bit;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bit) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
/* The bit requested is larger than all bits in this set */
if (bit >= intern->bitset_len * CHAR_BIT) {
zend_throw_exception_ex(spl_ce_OutOfRangeException, 0,
"The specified index parameter exceeds the total number of bits available");
RETURN_THROWS();
}
if (intern->bitset_val[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT))) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string BitSet::getRawValue(void)
*/
PHP_METHOD(BitSet, getRawValue)
{
php_bitset_object *intern;
intern = bitset_get_intern_object(getThis());
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if (intern->bitset_val) {
RETURN_STRINGL((char *) intern->bitset_val, intern->bitset_len);
} else {
RETURN_EMPTY_STRING();
}
}
/* }}} */
/* {{{ proto string BitSet::fromRawValue(void)
*/
PHP_METHOD(BitSet, fromRawValue)
{
php_bitset_object *newobj;
zend_class_entry *ce = bitset_class_entry;
zend_string *str;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
RETURN_THROWS();
}
newobj = php_bitset_object_new(ce);
if (str->len == 0) {
bitset_initialize_object(newobj, BITSET_DEFAULT_BITS);
return;
}
bitset_initialize_object(newobj, (str->len * CHAR_BIT));
memcpy(newobj->bitset_val, str->val, str->len);
ZVAL_OBJ(return_value, &newobj->zo);
}
/* }}} */
/* {{{ proto bool BitSet::intersects(BitSet set)
Determines if the provided value has any bits set to true that are also true in this object */
PHP_METHOD(BitSet, intersects)
{
php_bitset_object *a, *b;
zval *param_id;
long bitset_len1, bitset_len2, i, to_bits;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &param_id, bitset_class_entry) == FAILURE) {
RETURN_THROWS();
}
a = bitset_get_intern_object(getThis());
b = bitset_get_intern_object(param_id);
bitset_len1 = a->bitset_len;
bitset_len2 = b->bitset_len;
to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1;
for (i = 0; i < to_bits; i++) {
/* If the bits is set in both */
if (a->bitset_val[i] & b->bitset_val[i]) {
RETURN_TRUE;
}
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool BitSet::isEmpty(void)
Determines if this value contains no bits */
PHP_METHOD(BitSet, isEmpty)
{
php_bitset_object *intern;
long total_bits, i;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
total_bits = intern->bitset_len;
/* Loop through all bits and determine if there is a true bit. */
for (i = 0; i < total_bits; i++) {
if (intern->bitset_val[i]) {
RETURN_FALSE;
}
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int BitSet::length(void)
Returns the highest set bit plus one
*/
PHP_METHOD(BitSet, length)
{
php_bitset_object *intern;
long highest_bit = -1, i;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
i = intern->bitset_len * CHAR_BIT;
while (i > 0) {
i--;
if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) {
highest_bit = i;
break;
}
}
RETURN_LONG(highest_bit + 1);
}
/* }}} */
/* {{{ proto int BitSet::nextClearBit(int index)
Returns the index of the next bit after the provided index that is set to false */
PHP_METHOD(BitSet, nextClearBit)
{
php_bitset_object *intern;
zend_long start_bit = 0;
long bit_diff = 0, next_bit = 0;
short found = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
bit_diff = intern->bitset_len * CHAR_BIT;
if (start_bit >= bit_diff - 1) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"There are no bits larger than the index provided");
RETURN_THROWS();
}
start_bit++;
while (start_bit <= bit_diff) {
if (!(intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT)))) {
next_bit = start_bit;
found = 1;
break;
}
start_bit++;
}
if (found) {
RETURN_LONG(next_bit);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int BitSet::nextSetBit(int index)
Returns the index of the next bit after the provided index that is set to true */
PHP_METHOD(BitSet, nextSetBit)
{
php_bitset_object *intern;
zend_long start_bit = 0;
long bit_diff = 0, next_bit = 0;
short found = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
bit_diff = intern->bitset_len * CHAR_BIT;
if (start_bit >= bit_diff - 1) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"There are no bits larger than the index provided");
RETURN_THROWS();
}
start_bit++;
while (start_bit <= bit_diff) {
if (intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT))) {
next_bit = start_bit;
found = 1;
break;
}
start_bit++;
}
if (found) {
RETURN_LONG(next_bit);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto void BitSet::orOp(BitSet set)
Performs a logical OR of this object with the provided argument object */
PHP_METHOD(BitSet, orOp)
{
php_bitset_object *intern, *param;
zval *param_id;
long bitset_len1, bitset_len2, i, to_bits;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &param_id, bitset_class_entry) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
param = bitset_get_intern_object(param_id);
bitset_len1 = intern->bitset_len;
bitset_len2 = param->bitset_len;
to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1;
for (i = 0; i < to_bits; i++) {
intern->bitset_val[i] |= param->bitset_val[i];
}
}
/* }}} */
/* {{{ proto int BitSet::previousClearBit(int index)
Returns the index of the previous bit before the provided index that is set to false */
PHP_METHOD(BitSet, previousClearBit)
{
php_bitset_object *intern;
long start_bit = 0, bit_diff = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) {
RETURN_THROWS();
}
if (start_bit < 1) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"There are no bits smaller than the index provided");
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
bit_diff = intern->bitset_len * CHAR_BIT;
if (start_bit > bit_diff) {
zend_throw_exception_ex(spl_ce_OutOfRangeException, 0,
"The specified index parameter exceeds the total number of bits available");
RETURN_THROWS();
}
start_bit--;
while (start_bit >= 0) {
if (!(intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT)))) {
break;
}
start_bit--;
}
if (start_bit < 0) {
RETURN_FALSE;
} else {
RETURN_LONG(start_bit);
}
}
/* }}} */
/* {{{ proto int BitSet::previousSetBit(int index)
Returns the index of the previous bit before the provided index that is set to true */
PHP_METHOD(BitSet, previousSetBit)
{
php_bitset_object *intern;
zend_long start_bit = 0;
long bit_diff = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &start_bit) == FAILURE) {
RETURN_THROWS();
}
if (start_bit < 1) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"There are no bits smaller than the index provided");
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
bit_diff = intern->bitset_len * CHAR_BIT;
if (start_bit > bit_diff) {
zend_throw_exception_ex(spl_ce_OutOfRangeException, 0,
"The specified index parameter exceeds the total number of bits available");
RETURN_THROWS();
}
start_bit--;
while (start_bit >= 0) {
if (intern->bitset_val[start_bit / CHAR_BIT] & (1 << (start_bit % CHAR_BIT))) {
break;
}
start_bit--;
}
if (start_bit < 0) {
RETURN_FALSE;
} else {
RETURN_LONG(start_bit);
}
}
/* }}} */
/* {{{ proto void BitSet::set([int indexOrFromIndex[, toIndex]])
Sets the bits from the specified index or range to true
*/
PHP_METHOD(BitSet, set)
{
php_bitset_object *intern;
zend_long index_from = -1, index_to = 0;
long usable_index = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &index_from, &index_to) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
/* Set all bits */
if (index_from == -1 && index_to == 0) {
for (; usable_index < intern->bitset_len * CHAR_BIT; usable_index++)
{
intern->bitset_val[usable_index / CHAR_BIT] |= (1 << (usable_index % CHAR_BIT));
}
intern->bitset_val[intern->bitset_len] = '\0';
} else {
/* Verify the start index is not greater than total bits */
if (index_from > (intern->bitset_len * CHAR_BIT - 1)) {
zend_throw_exception_ex(spl_ce_OutOfRangeException, 0,
"The requested start index is greater than the total number of bits");
RETURN_THROWS();
}
if (index_to == 0) {
usable_index = index_from;
} else {
usable_index = index_to > intern->bitset_len * CHAR_BIT ? intern->bitset_len * CHAR_BIT : index_to;
}
for (; index_from <= usable_index; index_from++) {
intern->bitset_val[index_from / CHAR_BIT] |= (1 << (index_from % CHAR_BIT));
}
}
}
/* }}} */
/* {{{ proto int BitSet::size(void)
Returns the number of bits of space in use */
PHP_METHOD(BitSet, size)
{
php_bitset_object *intern;
intern = bitset_get_intern_object(getThis());
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
RETURN_LONG(intern->bitset_len * CHAR_BIT);
}
/* }}} */
/* {{{ proto BitSet BitSet::fromString(string)
* Returns a new instance of BitSet based on the provided string
*/
PHP_METHOD(BitSet, fromString)
{
php_bitset_object *newobj;
zend_class_entry *ce = bitset_class_entry;
zend_string *str = NULL;
int i;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
RETURN_THROWS();
}
newobj = php_bitset_object_new(ce);
if (str->len > 0) {
bitset_initialize_object(newobj, str->len);
} else {
bitset_initialize_object(newobj, BITSET_DEFAULT_BITS);
}
for (i = 0; i < str->len; i++) {
/* If the char is explicitly '1', set it as 1. Otherwise, it's 0 */
if (str->val[i] == '1') {
newobj->bitset_val[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
}
}
ZVAL_OBJ(return_value, &newobj->zo);
}
/* }}} */
/* {{{ proto BitSet BitSet::fromArray(array inputArray)
* Returns a new Bitset instance based on the input array. All positive integers
* within the array values are considered positions of set bits
*/
PHP_METHOD(BitSet, fromArray)
{
php_bitset_object *newobj;
zval *bit_array;
zval *entry;
zend_class_entry *ce = bitset_class_entry;
long array_len, highest_value, entry_actual;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &bit_array) == FAILURE) {
RETURN_THROWS();
}
array_len = zend_hash_num_elements(Z_ARRVAL_P(bit_array));
newobj = php_bitset_object_new(ce);
if (array_len == 0) {
bitset_initialize_object(newobj, BITSET_DEFAULT_BITS);
return;
}
highest_value = bitset_get_highest_value_from_array(bit_array);
bitset_initialize_object(newobj, highest_value+1);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(bit_array), entry) {
zend_long entry_long = zval_get_long(entry);
if (entry_long >= 0) {
entry_actual = entry_long / CHAR_BIT;
newobj->bitset_val[entry_actual] |= (1 << (entry_long % CHAR_BIT));
}
} ZEND_HASH_FOREACH_END();
ZVAL_OBJ(return_value, &newobj->zo);
}
/* }}} */
/* {{{ proto array BitSet::toArray(void)
Returns the on bits as an array */
PHP_METHOD(BitSet, toArray)
{
php_bitset_object *intern;
long i, total_bits;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
array_init(return_value);
total_bits = intern->bitset_len * CHAR_BIT;
for (i = 0; i < total_bits; i++) {
if (intern->bitset_val[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) {
add_next_index_long(return_value, i);
}
}
}
/* }}} */
/* {{{ proto BitSet BitSet::fromInteger(integer value)
* Returns a new Bitset instance based on the input value
*/
PHP_METHOD(BitSet, fromInteger)
{
php_bitset_object *newobj;
zend_class_entry *ce = bitset_class_entry;
zend_long value;
int i;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
RETURN_THROWS();
}
newobj = php_bitset_object_new(ce);
bitset_initialize_object(newobj, sizeof(value) * CHAR_BIT);
for (i = 0; i < sizeof(value) ; i++) {
newobj->bitset_val[i] = value & ((1 << CHAR_BIT) -1);
value >>= CHAR_BIT;
}
ZVAL_OBJ(return_value, &newobj->zo);
}
/* }}} */
/* {{{ proto integer BitSet::toInteger(void)
Returns the on bits as an integer */
PHP_METHOD(BitSet, toInteger)
{
php_bitset_object *intern;
int i;
zend_long value = 0;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
if (intern->bitset_len > sizeof(value)) {
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
"The total bits doesn't fit in an integer");
RETURN_THROWS();
}
for (i = 0; i < intern->bitset_len; i++) {
value |= intern->bitset_val[i] << (i * CHAR_BIT);
}
RETURN_LONG(value);
}
/* }}} */
/* {{{ proto void BitSet::xorOp(BitSet set)
Performs an XOR operation against the current object bit set with the specified argument */
PHP_METHOD(BitSet, xorOp)
{
php_bitset_object *intern, *param;
zval *param_id;
long bitset_len1, bitset_len2, i, to_bits;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &param_id, bitset_class_entry) == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
param = bitset_get_intern_object(param_id);
bitset_len1 = intern->bitset_len;
bitset_len2 = param->bitset_len;
to_bits = bitset_len1 > bitset_len2 ? bitset_len2 : bitset_len1;
for (i = 0; i < to_bits; i++) {
intern->bitset_val[i] ^= param->bitset_val[i];
}
}
/* }}} */
/* {{{ proto string BitSet::__toString(void)
Returns a human-readable string representation of the bit set */
PHP_METHOD(BitSet, __toString)
{
php_bitset_object *intern = NULL;
zend_string *retval;
char *internval = NULL;
long len, i;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
intern = bitset_get_intern_object(getThis());
if (intern->bitset_len == 0) {
RETURN_EMPTY_STRING();
} else {
len = intern->bitset_len * CHAR_BIT;
retval = zend_string_alloc(len, 0);
internval = ZSTR_VAL(retval);
internval[len] = '\0';
for (i = 0; i < len; i++) {
internval[i] = ((intern->bitset_val[i / CHAR_BIT] >> (i % CHAR_BIT)) & 1) ? '1' : '0';
}
RETURN_STR(retval);
}
}
/* }}} */
/* {{{ php_bitset_object *bitset_get_intern_object
*/
static php_bitset_object *bitset_get_intern_object(zval *object)
{
zend_object *obj = Z_OBJ_P(object);
return php_bitset_fetch_object(obj);
}
/* }}} */
/* {{{ long bitset_get_highest_value_from_array
*/
static long bitset_get_highest_value_from_array(zval *arr)
{
zval *entry;
long highest_value = 0;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), entry) {
zend_long entry_long = zval_get_long(entry);
if (entry_long > highest_value) {
highest_value = entry_long;
}
} ZEND_HASH_FOREACH_END();
return highest_value;
}
/* }}} */
/* {{{ php_bitset_object php_bitset_object_new
*/
static php_bitset_object *php_bitset_object_new(zend_class_entry *ce)
{
php_bitset_object *intern;
intern = ecalloc(1, sizeof(php_bitset_object) + zend_object_properties_size(ce));
intern->bitset_val = 0;
zend_object_std_init(&intern->zo, ce);
object_properties_init(&intern->zo, ce);
intern->zo.handlers = &bitset_object_handlers;
return intern;
}
/* }}} */
/* {{{ void bitset_initialize_object
*/
static void bitset_initialize_object(php_bitset_object *intern, long bits)
{
intern->bitset_len = (bits + CHAR_BIT - 1) / CHAR_BIT;
intern->bitset_val = (unsigned char *) emalloc(intern->bitset_len + 1);
memset(intern->bitset_val, 0, intern->bitset_len);
intern->bitset_val[intern->bitset_len] = '\0';
}
/* }}} */
/* {{{ bitset_destroy_object
*/
static void bitset_destroy_object(zend_object *obj)
{
zend_objects_destroy_object(obj);
}
/* }}} */
/* {{{ void bitset_free_object
*/
static void bitset_free_object(zend_object *obj)
{
php_bitset_object *bitset_obj;
bitset_obj = php_bitset_fetch_object(obj);
if (bitset_obj->bitset_val) {
efree(bitset_obj->bitset_val);
}
zend_object_std_dtor(obj);
}
/* }}} */
/* {{{ zend_object bitset_create_object
*/
static zend_object *bitset_create_object(zend_class_entry *ce)
{
php_bitset_object *intern;
intern = ecalloc(1, sizeof(php_bitset_object) + zend_object_properties_size(ce));
intern->bitset_val = 0;
zend_object_std_init(&intern->zo, ce);
object_properties_init(&intern->zo, ce);
intern->zo.handlers = &bitset_object_handlers;
return &intern->zo;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(bitset)
{
php_info_print_table_start();
php_info_print_table_header(2, "BitSet Support", "enabled");
php_info_print_table_row(2, "BitSet Version", PHP_BITSET_VERSION);
php_info_print_table_row(2, "64-bit Integer Support", sizeof(unsigned long long) == 8 ? "yes" : "no");
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(bitset)
{
bitset_class_entry = register_class_BitSet();
bitset_class_entry->create_object = bitset_create_object;
memcpy(&bitset_object_handlers, zend_get_std_object_handlers(), sizeof(bitset_object_handlers));
bitset_object_handlers.free_obj = bitset_free_object;
bitset_object_handlers.dtor_obj = bitset_destroy_object;
bitset_object_handlers.offset = XtOffsetOf(php_bitset_object, zo);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(bitset)
{
bitset_class_entry = NULL;
return SUCCESS;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/