Re: cvs: php-src /ext/spl spl_observer.c /ext/spl/internal splobjectstorage.inc /ext/spl/tests observer_002.phpt
| From: | Marcus Boerger | Date: | Wed, 10 Aug 2005 22:20:40 +0000 |
| Subject: | Re: cvs: php-src /ext/spl spl_observer.c /ext/spl/internal splobjectstorage.inc /ext/spl/tests observer_002.phpt | ||
| References: | 1 2 | Groups: | php.cvs |
| Request: | Send a blank email to php-cvs+get-33280@lists.php.net to get a copy of this message | ||
Hello Andrey,
thanks! I wanted to do it earlier but had no idea how to sole the problem.
I actually right from the beginning wanted to do all three in there. Anyway
you might also want to see t he last slides of my last presentation (the one
from OSCON) which you can find here: http://talks.somabo.de/
best regards
marcus
Thursday, August 11, 2005, 12:04:37 AM, you wrote:
> Wonderful idea Helly!
> Andrey
> Marcus Boerger wrote:
>> helly Wed Aug 10 17:56:02 2005 EDT
>>
>> Added files:
>> /php-src/ext/spl/internal splobjectstorage.inc
>> /php-src/ext/spl/tests observer_002.phpt
>>
>> Modified files:
>> /php-src/ext/spl spl_observer.c
>> Log:
>> - Implement SplObjectStorage as announced during OSCON
>> # This class starts naming of new classes in Spl by prefix Spl as dicussed.
>> # The class reduces object storage complexity from O(n) to O(1) which is
>> # not possible in user space.
>>
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>>
>> http://cvs.php.net/diff.php/php-src/ext/spl/spl_observer.c?r1=1.2&r2=1.3&ty=u
>> Index: php-src/ext/spl/spl_observer.c
>> diff -u php-src/ext/spl/spl_observer.c:1.2 php-src/ext/spl/spl_observer.c:1.3
>> --- php-src/ext/spl/spl_observer.c:1.2 Wed Aug 3 10:07:53 2005
>> +++ php-src/ext/spl/spl_observer.c Wed Aug 10 17:56:00 2005
>> @@ -16,7 +16,7 @@
>>
>> +----------------------------------------------------------------------+
>> */
>>
>> -/* $Id: spl_observer.c,v 1.2 2005/08/03 14:07:53 sniper Exp $ */
>> +/* $Id: spl_observer.c,v 1.3 2005/08/10 21:56:00 helly Exp $ */
>>
>> #ifdef HAVE_CONFIG_H
>> # include "config.h"
>> @@ -32,6 +32,8 @@
>> #include "spl_functions.h"
>> #include "spl_engine.h"
>> #include "spl_observer.h"
>> +#include "spl_iterators.h"
>> +#include "spl_array.h"
>>
>> SPL_METHOD(Observer, update);
>> SPL_METHOD(Subject, attach);
>> @@ -65,14 +67,197 @@
>> {NULL, NULL, NULL}
>> };
>>
>> -PHPAPI zend_class_entry *spl_ce_Observer;
>> -PHPAPI zend_class_entry *spl_ce_Subject;
>> +PHPAPI zend_class_entry *spl_ce_Observer;
>> +PHPAPI zend_class_entry *spl_ce_Subject;
>> +PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
>> +PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
>> +
>> +typedef struct _spl_SplObjectStorage {
>> + zend_object std;
>> + HashTable storage;
>> + long index;
>> + HashPosition pos;
>> +} spl_SplObjectStorage;
>> +
>> +/* storage is an assoc aray of [zend_object_value]=>[zval*] */
>> +
>> +void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
>> +{
>> + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
>> +
>> + zend_hash_destroy(intern->std.properties);
>> + FREE_HASHTABLE(intern->std.properties);
>> +
>> + zend_hash_destroy(&intern->storage);
>> +
>> + efree(object);
>> +} /* }}} */
>> +
>> +static zend_object_value spl_object_storage_new_ex(zend_class_entry
>> *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
>> +{
>> + zend_object_value retval;
>> + spl_SplObjectStorage *intern;
>> + zval *tmp;
>> +
>> + intern = emalloc(sizeof(spl_SplObjectStorage));
>> + memset(intern, 0, sizeof(spl_SplObjectStorage));
>> + intern->std.ce = class_type;
>> + *obj = intern;
>> +
>> + ALLOC_HASHTABLE(intern->std.properties);
>> + zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
>> + zend_hash_copy(intern->std.properties,
>> &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void
>> *) &tmp, sizeof(zval *));
>> +
>> + zend_hash_init(&intern->storage, 0, NULL, ZVAL_PTR_DTOR, 0);
>> +
>> + retval.handle = zend_objects_store_put(intern, NULL,
>> (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage,
>> NULL TSRMLS_CC);
>> + retval.handlers = &spl_handler_SplObjectStorage;
>> + return retval;
>> +}
>> +/* }}} */
>> +
>> +/* {{{ spl_array_object_new */
>> +static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
>> +{
>> + spl_SplObjectStorage *tmp;
>> + return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
>> +}
>> +/* }}} */
>> +
>> +/* {{{ proto void SplObjectStorage::attach($obj)
>> + Attaches an object to the storage if not yet contained */
>> +SPL_METHOD(SplObjectStorage, attach)
>> +{
>> + zval *obj;
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) ==
>> FAILURE) {
>> + return;
>> + }
>> +
>> + zend_hash_update(&intern->storage, (char*)&obj->value.obj,
>> sizeof(obj->value.obj), &obj, sizeof(zval**), NULL);
>> + obj->refcount++;
>> +} /* }}} */
>> +
>> +/* {{{ proto void SplObjectStorage::detach($obj)
>> + Detaches an object from the storage */
>> +SPL_METHOD(SplObjectStorage, detach)
>> +{
>> + zval *obj;
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) ==
>> FAILURE) {
>> + return;
>> + }
>> +
>> + zend_hash_del(&intern->storage, (char*)&obj->value.obj,
>> sizeof(obj->value.obj));
>> + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
>> + intern->index = 0;
>> +} /* }}} */
>> +
>> +/* {{{ proto bool SplObjectStorage::contains($obj)
>> + Determine whethe an object is contained in the storage */
>> +SPL_METHOD(SplObjectStorage, contains)
>> +{
>> + zval *obj;
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) ==
>> FAILURE) {
>> + return;
>> + }
>> +
>> + RETURN_BOOL(zend_hash_exists(&intern->storage,
>> (char*)&obj->value.obj, sizeof(obj->value.obj)));
>> +} /* }}} */
>> +
>> +/* {{{ proto int SplObjectStorage::count()
>> + Determine number of objects in storage */
>> +SPL_METHOD(SplObjectStorage, count)
>> +{
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + RETURN_LONG(zend_hash_num_elements(&intern->storage));
>> +} /* }}} */
>> +
>> +/* {{{ proto void SplObjectStorage::rewind()
>> + */
>> +SPL_METHOD(SplObjectStorage, rewind)
>> +{
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
>> + intern->index = 0;
>> +} /* }}} */
>> +
>> +/* {{{ proto bool SplObjectStorage::valid()
>> + */
>> +SPL_METHOD(SplObjectStorage, valid)
>> +{
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage,
>> &intern->pos) == SUCCESS);
>> +} /* }}} */
>> +
>> +/* {{{ proto mixed SplObjectStorage::key()
>> + */
>> +SPL_METHOD(SplObjectStorage, key)
>> +{
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + RETURN_LONG(intern->index);
>> +} /* }}} */
>> +
>> +/* {{{ proto mixed SplObjectStorage::current()
>> + */
>> +SPL_METHOD(SplObjectStorage, current)
>> +{
>> + zval **entry;
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + if (zend_hash_get_current_data_ex(&intern->storage,
>> (void**)&entry, &intern->pos) == FAILURE) {
>> + return;
>> + }
>> + RETVAL_ZVAL(*entry, 1, 0);
>> +} /* }}} */
>> +
>> +/* {{{ proto void SplObjectStorage::next()
>> + */
>> +SPL_METHOD(SplObjectStorage, next)
>> +{
>> + spl_SplObjectStorage *intern =
>> (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
>> +
>> + zend_hash_move_forward_ex(&intern->storage, &intern->pos);
>> + intern->index++;
>> +} /* }}} */
>> +
>> +static
>> +ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
>> + ZEND_ARG_INFO(0, object 0)
>> +ZEND_END_ARG_INFO();
>> +
>> +static zend_function_entry spl_funcs_SplObjectStorage[] = {
>> + SPL_ME(SplObjectStorage, attach, arginfo_Object, 0)
>> + SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
>> + SPL_ME(SplObjectStorage, contains, arginfo_Object, 0)
>> + SPL_ME(SplObjectStorage, count, NULL, 0)
>> + SPL_ME(SplObjectStorage, rewind, NULL, 0)
>> + SPL_ME(SplObjectStorage, valid, NULL, 0)
>> + SPL_ME(SplObjectStorage, key, NULL, 0)
>> + SPL_ME(SplObjectStorage, current, NULL, 0)
>> + SPL_ME(SplObjectStorage, next, NULL, 0)
>> + {NULL, NULL, NULL}
>> +};
>>
>> /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
>> PHP_MINIT_FUNCTION(spl_observer)
>> {
>> REGISTER_SPL_INTERFACE(Observer);
>> REGISTER_SPL_INTERFACE(Subject);
>> +
>> + REGISTER_SPL_STD_CLASS_EX(SplObjectStorage,
>> spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
>> + memcpy(&spl_handler_SplObjectStorage,
>> zend_get_std_object_handlers(), sizeof(zend_object_handlers));
>> +
>> + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
>> + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
>>
>> return SUCCESS;
>> }
>>
>> ÇàpÅù
>> r¥Œ/hP»@¥http://cvs.php.net/co.php/php-src/ext/spl/internal/splobjectstorage.inc?r=1.1&p=1
>> Index: php-src/ext/spl/internal/splobjectstorage.inc
>> +++ php-src/ext/spl/internal/splobjectstorage.inc
>> <?php
>>
>> /** @file splobjectstorage.inc
>> * @ingroup SPL
>> * @brief class SplObjectStorage
>> * @author Marcus Boerger
>> * @date 2003 - 2005
>> *
>> * SPL - Standard PHP Library
>> */
>>
>> /**
>> * @brief Object storage
>> * @author Marcus Boerger
>> * @version 1.0
>> * @since PHP 6.0
>> *
>> * This container allows to store objects uniquly without the need to compare
>> * them one by one. This is only possible internally. The code represenation
>> * here therefore has a complexity of O(n) while the actual implementation has
>> * complexity O(1).
>> */
>> class SplObjectStorage implements Iterator, Countable
>> {
>> private $storage = array();
>> private $index = 0;
>>
>> /** Rewind to top iterator as set in constructor
>> */
>> function rewind()
>> {
>> rewind($this->storage);
>> }
>>
>> /** @return whether iterator is valid
>> */
>> function valid()
>> {
>> return key($this->storage) !== false;
>> }
>>
>> /** @return current key
>> */
>> function key()
>> {
>> return $this->index;
>> }
>>
>> /** @return current object
>> */
>> function current()
>> {
>> return current($this->storage);
>> }
>>
>> /** Forward to next element
>> */
>> function next()
>> {
>> next($this->storage);
>> $this->index++;
>> }
>>
>> /** @return number of objects in storage
>> */
>> function count()
>> {
>> return count($this->storage);
>> }
>>
>> /** @obj object to look for
>> * @return whether $obj is contained in storage
>> */
>> function contains($obj)
>> {
>> if (is_object($obj))
>> {
>> foreach($this->storage as $object)
>> {
>> if ($object === $obj)
>> {
>> return true;
>> }
>> }
>> }
>> return false;
>> }
>>
>> /** @param $obj new object to attach to storage if not yet contained
>> */
>> function attach($obj)
>> {
>> if (is_object($obj) && !$this->contains($obj))
>> {
>> $this->storage[] = $obj;
>> }
>> }
>>
>> /** @param $obj object to remove from storage
>> */
>> function detach($obj)
>> {
>> if (is_object($obj))
>> {
>> foreach($this->storage as $idx => $object)
>> {
>> if ($object === $obj)
>> {
>> unset($this->storage[$idx]);
>> $this->rewind();
>> return;
>> }
>> }
>> }
>> }
>> }
>>
>> ?>
>>
>> http://cvs.php.net/co.php/php-src/ext/spl/tests/observer_002.phpt?r=1.1&p=1
>> Index: php-src/ext/spl/tests/observer_002.phpt
>> +++ php-src/ext/spl/tests/observer_002.phpt
>> --TEST--
>> SPL: SplObjectStorage
>> --FILE--
>> <?php
>>
>> class MyObjectStorage extends SplObjectStorage
>> {
>> function rewind()
>> {
>> echo __METHOD__ . "()\n";
>> parent::rewind();
>> }
>>
>> function valid()
>> {
>> echo __METHOD__ . "(" . (parent::valid() ? 1 : 0) .
>> ")\n";
>> return parent::valid();
>> }
>>
>> function key()
>> {
>> echo __METHOD__ . "(" . parent::key() . ")\n";
>> return parent::key();
>> }
>>
>> function current()
>> {
>> echo __METHOD__ . "(" . parent::current()->getName() .
>> ")\n";
>> return parent::current();
>> }
>>
>> function next()
>> {
>> echo __METHOD__ . "()\n";
>> parent::next();
>> }
>> }
>>
>> class ObserverImpl implements Observer
>> {
>> protected $name = '';
>>
>> function __construct($name = 'obj')
>> {
>> $this->name = '$' . $name;
>> }
>>
>> function update(Subject $subject)
>> {
>> echo $this->name . '->' . __METHOD__ . '(' .
>> $subject->getName() . ");\n";
>> }
>>
>> function getName()
>> {
>> return $this->name;
>> }
>> }
>>
>> class SubjectImpl implements Subject
>> {
>> protected $name = '';
>> protected $observers;
>>
>> function __construct($name = 'sub')
>> {
>> $this->observers = new MyObjectStorage;
>> $this->name = '$' . $name;
>> }
>>
>> function attach(Observer $observer)
>> {
>> echo $this->name . '->' . __METHOD__ . '(' .
>> $observer->getName() . ");\n";
>> $this->observers->attach($observer);
>> }
>>
>> function detach(Observer $observer)
>> {
>> echo $this->name . '->' . __METHOD__ . '(' .
>> $observer->getName() . ");\n";
>> $this->observers->detach($observer);
>> }
>>
>> function count()
>> {
>> return $this->observers->count();
>> }
>>
>> function notify()
>> {
>> echo $this->name . '->' . __METHOD__ . "();\n";
>> foreach($this->observers as $key => $observer)
>> {
>> $observer->update($this);
>> }
>> }
>>
>> function getName()
>> {
>> return $this->name;
>> }
>>
>> function contains($obj)
>> {
>> return $this->observers->contains($obj);
>> }
>> }
>>
>> $sub = new SubjectImpl;
>>
>> $ob1 = new ObserverImpl("ob1");
>> $ob2 = new ObserverImpl("ob2");
>> $ob3 = new ObserverImpl("ob3");
>>
>> var_dump($sub->contains($ob1));
>> $sub->attach($ob1);
>> var_dump($sub->contains($ob1));
>> $sub->attach($ob1);
>> $sub->attach($ob2);
>> $sub->attach($ob3);
>> var_dump($sub->count());
>>
>> $sub->notify();
>>
>> $sub->detach($ob3);
>> var_dump($sub->count());
>>
>> $sub->notify();
>>
>> $sub->detach($ob2);
>> $sub->detach($ob1);
>> var_dump($sub->count());
>>
>> $sub->notify();
>>
>> $sub->attach($ob3);
>> var_dump($sub->count());
>>
>> $sub->notify();
>>
>> ?>
>> ===DONE===
>> <?php exit(0); ?>
>> --EXPECT--
>> bool(false)
>> $sub->SubjectImpl::attach($ob1);
>> bool(true)
>> $sub->SubjectImpl::attach($ob1);
>> $sub->SubjectImpl::attach($ob2);
>> $sub->SubjectImpl::attach($ob3);
>> int(3)
>> $sub->SubjectImpl::notify();
>> MyObjectStorage::rewind()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob1)
>> MyObjectStorage::key(0)
>> $ob1->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob2)
>> MyObjectStorage::key(1)
>> $ob2->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob3)
>> MyObjectStorage::key(2)
>> $ob3->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(0)
>> $sub->SubjectImpl::detach($ob3);
>> int(2)
>> $sub->SubjectImpl::notify();
>> MyObjectStorage::rewind()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob1)
>> MyObjectStorage::key(0)
>> $ob1->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob2)
>> MyObjectStorage::key(1)
>> $ob2->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(0)
>> $sub->SubjectImpl::detach($ob2);
>> $sub->SubjectImpl::detach($ob1);
>> int(0)
>> $sub->SubjectImpl::notify();
>> MyObjectStorage::rewind()
>> MyObjectStorage::valid(0)
>> $sub->SubjectImpl::attach($ob3);
>> int(1)
>> $sub->SubjectImpl::notify();
>> MyObjectStorage::rewind()
>> MyObjectStorage::valid(1)
>> MyObjectStorage::current($ob3)
>> MyObjectStorage::key(0)
>> $ob3->ObserverImpl::update($sub);
>> MyObjectStorage::next()
>> MyObjectStorage::valid(0)
>> ===DONE===
>>
>>
Best regards,
Marcus