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