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; >> } >> >> 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 -- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php