summaryrefslogtreecommitdiff
path: root/zend/hashiterator.h
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 21:53:24 +0200
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-04-06 21:53:24 +0200
commit35fd3ccbeb4def71b4d8a59dfbb5c31201b099b9 (patch)
tree915223360aed4743aa6127fde4836aa413a260e5 /zend/hashiterator.h
parentda4710512865e6816585ac4ab8edab2fa125e2d8 (diff)
renamed src directory to zend directory, disabled TSRM debug code
Diffstat (limited to 'zend/hashiterator.h')
-rw-r--r--zend/hashiterator.h250
1 files changed, 250 insertions, 0 deletions
diff --git a/zend/hashiterator.h b/zend/hashiterator.h
new file mode 100644
index 0000000..b1f409f
--- /dev/null
+++ b/zend/hashiterator.h
@@ -0,0 +1,250 @@
+/**
+ * HashIterator.h
+ *
+ * This is an internal helper class that is used when iterating over a
+ * Php::Value object that holds a hash table (an array or an object that
+ * does not implement the Traversable interface - stl style.
+ *
+ * Thus, when you do c++ things like "for (auto &iter : value)", internally
+ * a ValueIterator object is being used.
+ *
+ * @author Emiel Bruijntjes
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class HashIterator : public ValueIteratorImpl
+{
+public:
+ /**
+ * Constructor
+ * @param hashtable The hashtable to iterate over
+ * @param first Should it start on the first position?
+ * @param tsrm_ls
+ */
+ HashIterator(HashTable *hashtable, bool first) : _table(hashtable)
+ {
+ // reset the hash pointer to the internal position
+ if (hashtable && first)
+ {
+ // move to first position
+ zend_hash_internal_pointer_reset_ex(_table, &_position);
+
+ // read current data
+ if (read()) return;
+
+ // data was private, move on
+ increment();
+ }
+ else
+ {
+ // start with invalid data
+ invalidate();
+ }
+ }
+
+ /**
+ * Copy constructor
+ * @param that
+ * @param tsrm_ls
+ */
+ HashIterator(const HashIterator &that TSRMLS_DC) :
+ _table(that._table), _position(that._position)
+ {
+ // read current position
+ read();
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~HashIterator() {}
+
+ /**
+ * Clone the object
+ * @param tsrm_ls
+ * @return ValueIteratorImpl
+ */
+ virtual ValueIteratorImpl *clone()
+ {
+ // create a new instance
+ return new HashIterator(*this);
+ }
+
+ /**
+ * Increment position (pre-increment)
+ * @return bool
+ */
+ virtual bool increment() override
+ {
+ // leap out if already on an invalid pos (behind the last pos)
+ if (!_position) return false;
+
+ // move the iterator forward
+ if (zend_hash_move_forward_ex(_table, &_position) == SUCCESS)
+ {
+ // read current key and value
+ if (read()) return true;
+
+ // data was private or invalid, move further
+ return increment();
+ }
+ else
+ {
+ // invalidate current position
+ return invalidate();
+ }
+ }
+
+ /**
+ * Decrement position (pre-decrement)
+ * @return bool
+ */
+ virtual bool decrement() override
+ {
+ // leap out if we're not even iterating over a hash table
+ if (!_table) return false;
+
+ // if position is invalid, it is one position behind the last position
+ if (!_position)
+ {
+ // move to last position
+ zend_hash_internal_pointer_end_ex(_table, &_position);
+ }
+ else if (zend_hash_move_backwards_ex(_table, &_position) == FAILURE)
+ {
+ // invalidate current position
+ return invalidate();
+ }
+
+ // read current key and value
+ if (read()) return true;
+
+ // data was private, move on
+ return decrement();
+ }
+
+ /**
+ * Compare with other iterator
+ * @param that
+ * @return bool
+ */
+ virtual bool equals(const ValueIteratorImpl *that) const override
+ {
+ // this always is a hash iterator
+ HashIterator *other = (HashIterator *)that;
+
+ // compare the positions
+ return _position == other->_position;
+ }
+
+ /**
+ * Derefecence, this returns a std::pair with the current key and value
+ * @return std::pair
+ */
+ virtual const std::pair<Value,Value> &current() const override
+ {
+ return _current;
+ }
+
+private:
+ /**
+ * The hash table over which is being iterated
+ * @var HashTable
+ */
+ HashTable *_table = nullptr;
+
+ /**
+ * The position in the hash table
+ * @var HashPosition
+ */
+ Bucket *_position = nullptr;
+
+ /**
+ * The current key and value
+ * @var std::pair
+ */
+ std::pair<Value,Value> _current;
+
+ /**
+ * Read current key and value
+ * @return bool
+ */
+ bool read()
+ {
+ // zval to read the current key in
+ Value key;
+
+#if PHP_VERSION_ID >= 50500
+
+ // read in the current key
+ zend_hash_get_current_key_zval_ex(_table, key._val, &_position);
+
+ // if the key is set to NULL, it means that the object is not at a valid position
+ if (key.isNull()) return invalidate();
+
+#else
+
+ // php 5.3 and php 5.4 need a different implementation because the function
+ // zend_hash_get_current_key_zval_ex is missing in php 5.3, declare variables
+ // we need for storing the key in
+ char *string_key;
+ unsigned int str_len;
+ unsigned long num_key;
+
+ // get the current key
+ int type = zend_hash_get_current_key_ex(_table, &string_key, &str_len, &num_key, 0, &_position);
+
+ // if key is not found, the iterator is at an invalid position
+ if (type == HASH_KEY_NON_EXISTANT) return invalidate();
+
+ // numeric keys are the easiest ones
+ if (type == HASH_KEY_IS_LONG) key = (int64_t)num_key;
+ else key = string_key;
+
+#endif
+
+ // iterator is at a valid position, go fetch the data
+ // this is the variable we need for fetching the data
+ zval **value;
+
+ // retrieve data
+ zend_hash_get_current_data_ex(_table, (void **) &value, &_position);
+
+ // we can now update the current data
+ _current = std::make_pair<Value,Value>(std::move(key), *value);
+
+ // if the key is private (it starts with a null character) we should return
+ // false to report that the object is not in a completely valid state
+ return !_current.first.isString() || _current.first.rawValue()[0];
+ }
+
+ /**
+ * Invalidate the iterator
+ * @return bool
+ */
+ bool invalidate()
+ {
+ // forget current position
+ _position = nullptr;
+
+ // make the data a pair of null ptrs
+ _current = std::make_pair<Value,Value>(nullptr,nullptr);
+
+ // done
+ return false;
+ }
+};
+
+/**
+ * End namespace
+ */
+}
+