small refactor && update documentation
parent
394fdbf5f0
commit
8d9f4d773b
|
@ -1,2 +1,3 @@
|
|||
*.h linguist-language=C
|
||||
stubs/* linguist-documentation
|
||||
config.m4 linguist-detectable=false
|
||||
|
|
12
README.md
12
README.md
|
@ -31,6 +31,18 @@ The `Collection` class implements `ArrayAccess` and `Countable` interface intern
|
|||
* `empty()`, `count()` can be used on instance of `Collection`.
|
||||
* Elements can be traversed via `foreach()` keyword.
|
||||
|
||||
### 2.3 Copy-on-write mechanism
|
||||
|
||||
Class `Collection` does not introduce new data structures internally. Instead, it only holds a pointer to a `zend_array`, and all its methods works directly on top of `zend_array`. Which means conversion between `Collection` and `array` does not involve copying, until write operation is performed on one of the duplicates.
|
||||
|
||||
```php
|
||||
$foo = ['a', 'b']; // arr0: refcount = 1
|
||||
$bar = Collection::init($foo); // arr0: refcount = 2, no copying of either `zend_array` or its elements
|
||||
echo $bar->containsValue('a'); // arr0: refcount = 2, read operation, no copying
|
||||
$bar->shuffle(); // arr0: refcount = 1, arr1: refcount = 1, write operation, `zend_array` is separated
|
||||
$baz = $bar->toArray(); // arr0: refcount = 1, arr1: refcount = 2, no copying
|
||||
```
|
||||
|
||||
### 2.4 Notes
|
||||
|
||||
* The `Collection::xxxTo()` methods will preserve the original key-value pairs of destination `Collection` when keys collide.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define GC_DELREF(p) --GC_REFCOUNT(p)
|
||||
#endif
|
||||
|
||||
// Thread safty assured global variables.
|
||||
#define FCI_G COLLECTIONS_G(fci)
|
||||
#define FCC_G COLLECTIONS_G(fcc)
|
||||
#define REF_G COLLECTIONS_G(ref)
|
||||
|
@ -30,6 +31,7 @@
|
|||
#define IS_PAIR(val) \
|
||||
(Z_TYPE(val) == IS_OBJECT && Z_OBJCE(val) == collections_pair_ce)
|
||||
|
||||
// Separation on the zend_array held by the collection.
|
||||
#define SEPARATE_COLLECTION(ht, obj) \
|
||||
if (GC_REFCOUNT(ht) > 1) { \
|
||||
GC_DELREF(ht); \
|
||||
|
@ -40,11 +42,11 @@
|
|||
|
||||
#define INIT_FCI(fci, num_args) \
|
||||
zval params[num_args], retval; \
|
||||
(fci)->size = sizeof(zend_fcall_info); \
|
||||
(fci)->param_count = (num_args); \
|
||||
(fci)->retval = &retval; \
|
||||
(fci)->params = params
|
||||
|
||||
// Invoke callback function, passing bucket value as 1st arg, key as 2nd.
|
||||
#define CALLBACK_KEYVAL_INVOKE(params, bucket) \
|
||||
ZVAL_COPY_VALUE(&(params)[0], &(bucket)->val); \
|
||||
if ((bucket)->key) { \
|
||||
|
@ -54,6 +56,7 @@
|
|||
} \
|
||||
zend_call_function(&fci, &fcc)
|
||||
|
||||
// Several E_WARNING level error messages. Could use exceptions instead.
|
||||
#define PHP_COLLECTIONS_ERROR(type, msg) \
|
||||
php_error_docref(NULL, type, msg)
|
||||
#define ERR_BAD_ARGUMENT_TYPE() \
|
||||
|
@ -74,6 +77,7 @@
|
|||
PHP_COLLECTIONS_ERROR(E_WARNING, "The array should be packed")
|
||||
#define ERR_SILENCED()
|
||||
|
||||
// Validate and extract zend_array from collection.
|
||||
#define ELEMENTS_VALIDATE(elements, err, err_then) \
|
||||
zend_array* elements##_arr; \
|
||||
if (IS_COLLECTION(*elements)) { \
|
||||
|
@ -93,6 +97,7 @@
|
|||
#define ARRAY_CLONE(dest, src) \
|
||||
zend_array* (dest) = zend_array_dup(src);
|
||||
|
||||
// Creates a new collection which wraps the given zend_array.
|
||||
#define RETVAL_NEW_COLLECTION(ht) \
|
||||
{ \
|
||||
zend_object* _obj = create_collection_obj(); \
|
||||
|
@ -168,7 +173,7 @@ static zend_always_inline void array_update_bucket(zend_array* ht, Bucket* bucke
|
|||
static zend_always_inline zend_object* create_object(zend_class_entry* ce,
|
||||
zend_object_handlers* handlers)
|
||||
{
|
||||
zend_object* obj = (zend_object*)ecalloc(1, sizeof(zend_object) +
|
||||
zend_object* obj = (zend_object*)emalloc(sizeof(zend_object) +
|
||||
zend_object_properties_size(ce));
|
||||
zend_object_std_init(obj, ce);
|
||||
object_properties_init(obj, ce);
|
||||
|
@ -693,8 +698,6 @@ void collection_write_property(zval* object, zval* member, zval* value, void** u
|
|||
|
||||
zval* collection_read_dimension(zval* object, zval* offset, int type, zval* rv)
|
||||
{
|
||||
// Note that we don't handle type. So don't do any fancy things with Collection
|
||||
// such as fetching a reference of a value, etc.
|
||||
zend_array* current = Z_COLLECTION_P(object);
|
||||
zval* found = NULL;
|
||||
if (Z_TYPE_P(offset) == IS_LONG) {
|
||||
|
|
Reference in New Issue