diff options
Diffstat (limited to 'ext/spl/internal')
25 files changed, 2938 insertions, 0 deletions
diff --git a/ext/spl/internal/appenditerator.inc b/ext/spl/internal/appenditerator.inc new file mode 100644 index 0000000..28e32b1 --- /dev/null +++ b/ext/spl/internal/appenditerator.inc @@ -0,0 +1,122 @@ +<?php + +/** @file appenditerator.inc + * @ingroup SPL + * @brief class AppendIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator that iterates over several iterators one after the other + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +class AppendIterator implements OuterIterator +{ + /** @internal array of inner iterators */ + private $iterators; + + /** Construct an empty AppendIterator + */ + function __construct() + { + $this->iterators = new ArrayIterator(); + } + + /** Append an Iterator + * @param $it Iterator to append + * + * If the current state is invalid but the appended iterator is valid + * the AppendIterator itself becomes valid. However there will be no + * call to $it->rewind(). Also if the current state is invalid the inner + * ArrayIterator will be rewound und forwarded to the appended element. + */ + function append(Iterator $it) + { + $this->iterators->append($it); + } + + /** @return the current inner Iterator + */ + function getInnerIterator() + { + return $this->iterators->current(); + } + + /** Rewind to the first element of the first inner Iterator. + * @return void + */ + function rewind() + { + $this->iterators->rewind(); + if ($this->iterators->valid()) + { + $this->getInnerIterator()->rewind(); + } + } + + /** @return whether the current element is valid + */ + function valid() + { + return $this->iterators->valid() && $this->getInnerIterator()->valid(); + } + + /** @return the current value if it is valid or \c NULL + */ + function current() + { + /* Using $this->valid() would be exactly the same; it would omit + * the access to a non valid element in the inner iterator. Since + * the user didn't respect the valid() return value false this + * must be intended hence we go on. */ + return $this->iterators->valid() ? $this->getInnerIterator()->current() : NULL; + } + + /** @return the current key if it is valid or \c NULL + */ + function key() + { + return $this->iterators->valid() ? $this->getInnerIterator()->key() : NULL; + } + + /** Move to the next element. If this means to another Iterator that + * rewind that Iterator. + * @return void + */ + function next() + { + if (!$this->iterators->valid()) + { + return; /* done all */ + } + $this->getInnerIterator()->next(); + if ($this->getInnerIterator()->valid()) + { + return; /* found valid element in current inner iterator */ + } + $this->iterators->next(); + while ($this->iterators->valid()) + { + $this->getInnerIterator()->rewind(); + if ($this->getInnerIterator()->valid()) + { + return; /* found element as first elemet in another iterator */ + } + $this->iterators->next(); + } + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getInnerIterator(), $func), $params); + } +} + +?> diff --git a/ext/spl/internal/cachingiterator.inc b/ext/spl/internal/cachingiterator.inc new file mode 100644 index 0000000..33258ab --- /dev/null +++ b/ext/spl/internal/cachingiterator.inc @@ -0,0 +1,157 @@ +<?php + +/** @file cachingiterator.inc + * @ingroup SPL + * @brief class CachingIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Cached iteration over another Iterator + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.0 + * + * This iterator wrapper does a one ahead iteration. This way it knows whether + * the inner iterator has one more element. + * + * @note If you want to convert the elements into strings and the inner + * Iterator is an internal Iterator then you need to provide the + * flag CALL_TOSTRING to do the conversion when the actual element + * is being fetched. Otherwise the conversion would happen with the + * already changed iterator. If you do not need this then it you should + * omit this flag because it costs unneccessary work and time. + */ +class CachingIterator implements OuterIterator +{ + const CALL_TOSTRING = 0x00000001; + const CATCH_GET_CHILD = 0x00000002; + const TOSTRING_USE_KEY = 0x00000010; + const TOSTRING_USE_CURRENT = 0x00000020; + + private $it; + private $current; + private $key; + private $valid; + private $strValue; + + /** Construct from another iterator + * + * @param it Iterator to cache + * @param flags Bitmask: + * - CALL_TOSTRING (whether to call __toString() for every element) + */ + function __construct(Iterator $it, $flags = self::CALL_TOSTRING) + { + if ((($flags & self::CALL_TOSTRING) && ($flags & (self::TOSTRING_USE_KEY|self::TOSTRING_USE_CURRENT))) + || ((flags & (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)) == (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT))) + { + throw new InvalidArgumentException('Flags must contain only one of CIT_CALL_TOSTRING, CIT_TOSTRING_USE_KEY, CIT_TOSTRING_USE_CURRENT'); + } + $this->it = $it; + $this->flags = $flags & (0x0000FFFF); + $this->next(); + } + + /** Rewind the Iterator + */ + function rewind() + { + $this->it->rewind(); + $this->next(); + } + + /** Forward to the next element + */ + function next() + { + if ($this->valid = $this->it->valid()) { + $this->current = $this->it->current(); + $this->key = $this->it->key(); + if ($this->flags & self::CALL_TOSTRING) { + if (is_object($this->current)) { + $this->strValue = $this->current->__toString(); + } else { + $this->strValue = (string)$this->current; + } + } + } else { + $this->current = NULL; + $this->key = NULL; + $this->strValue = NULL; + } + $this->it->next(); + } + + /** @return whether the iterator is valid + */ + function valid() + { + return $this->valid; + } + + /** @return whether there is one more element + */ + function hasNext() + { + return $this->it->valid(); + } + + /** @return the current element + */ + function current() + { + return $this->current; + } + + /** @return the current key + */ + function key() + { + return $this->key; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } + + /** @return the string represenatation that was generated for the current + * element + * @throw exception when CALL_TOSTRING was not specified in constructor + */ + function __toString() + { + if ($this->flags & self::TOSTRING_USE_KEY) + { + return $this->key; + } + else if ($this->flags & self::TOSTRING_USE_CURRENT) + { + return $this->current; + } + if (!$this->flags & self::CALL_TOSTRING) + { + throw new exception('CachingIterator does not fetch string value (see CachingIterator::__construct)'); + } + return $this->strValue; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } +} + +?> diff --git a/ext/spl/internal/emptyiterator.inc b/ext/spl/internal/emptyiterator.inc new file mode 100644 index 0000000..ac80e79 --- /dev/null +++ b/ext/spl/internal/emptyiterator.inc @@ -0,0 +1,62 @@ +<?php + +/** @file emptyiterator.inc + * @ingroup SPL + * @brief class EmptyIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An empty Iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +class EmptyIterator implements Iterator +{ + /** No operation. + * @return void + */ + function rewind() + { + // nothing to do + } + + /** @return \c false + */ + function valid() + { + return false; + } + + /** This function must not be called. It throws an exception upon access. + * @throw Exception + * @return void + */ + function current() + { + throw new Exception('Accessing the value of an EmptyIterator'); + } + + /** This function must not be called. It throws an exception upon access. + * @throw Exception + * @return void + */ + function key() + { + throw new Exception('Accessing the key of an EmptyIterator'); + } + + /** No operation. + * @return void + */ + function next() + { + // nothing to do + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/filteriterator.inc b/ext/spl/internal/filteriterator.inc new file mode 100644 index 0000000..3330cc9 --- /dev/null +++ b/ext/spl/internal/filteriterator.inc @@ -0,0 +1,127 @@ +<?php + +/** @file filteriterator.inc + * @ingroup SPL + * @brief class FilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Abstract filter for iterators + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.0 + * + * Instances of this class act as a filter around iterators. In other words + * you can put an iterator into the constructor and the instance will only + * return selected (accepted) elements. + * + * The only thing that needs to be done to make this work is implementing + * method accept(). Typically this invloves reading the current element or + * key of the inner Iterator and checking whether it is acceptable. + */ +abstract class FilterIterator implements OuterIterator +{ + private $it; + + /** + * Constructs a filter around another iterator. + * + * @param it Iterator to filter + */ + function __construct(Iterator $it) { + $this->it = $it; + } + + /** + * Rewind the inner iterator. + */ + function rewind() { + $this->it->rewind(); + $this->fetch(); + } + + /** + * Accept function to decide whether an element of the inner iterator + * should be accessible through the Filteriterator. + * + * @return whether or not to expose the current element of the inner + * iterator. + */ + abstract function accept(); + + /** + * Fetch next element and store it. + * + * @return void + */ + protected function fetch() { + while ($this->it->valid()) { + if ($this->accept()) { + return; + } + $this->it->next(); + }; + } + + /** + * Move to next element + * + * @return void + */ + function next() { + $this->it->next(); + $this->fetch(); + } + + /** + * @return Whether more elements are available + */ + function valid() { + return $this->it->valid(); + } + + /** + * @return The current key + */ + function key() { + return $this->it->key(); + } + + /** + * @return The current value + */ + function current() { + return $this->it->current(); + } + + /** + * hidden __clone + */ + protected function __clone() { + // disallow clone + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/infiniteiterator.inc b/ext/spl/internal/infiniteiterator.inc new file mode 100644 index 0000000..04d7827 --- /dev/null +++ b/ext/spl/internal/infiniteiterator.inc @@ -0,0 +1,48 @@ +<?php + +/** @file infiniteiterator.inc + * @ingroup SPL + * @brief class InfiniteIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An infinite Iterator + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + * + * This Iterator takes another Iterator and infinitvely iterates it by + * rewinding it when its end is reached. + * + * \note Even an InfiniteIterator stops if its inner Iterator is empty. + * + \verbatim + $it = new ArrayIterator(array(1,2,3)); + $infinite = new InfiniteIterator($it); + $limit = new LimitIterator($infinite, 0, 5); + foreach($limit as $val=>$key) + { + echo "$val=>$key\n"; + } + \endverbatim + */ +class InfiniteIterator extends IteratorIterator +{ + /** Move the inner Iterator forward to its next element or rewind it. + * @return void + */ + function next() + { + $this->getInnerIterator()->next(); + if (!$this->getInnerIterator()->valid()) + { + $this->getInnerIterator()->rewind(); + } + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/iteratoriterator.inc b/ext/spl/internal/iteratoriterator.inc new file mode 100644 index 0000000..37676e0 --- /dev/null +++ b/ext/spl/internal/iteratoriterator.inc @@ -0,0 +1,121 @@ +<?php + +/** @file iteratoriterator.inc + * @ingroup SPL + * @brief class IteratorIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Basic Iterator wrapper + * @since PHP 5.1 + * + * This iterator wrapper allows to convert anything that is traversable into + * an Iterator. It is very important to understand that most classes that do + * not implement Iterator have their reasone to. Most likely they do not allow + * the full Iterator feature set. If so you need to provide techniques to + * prevent missuse. If you do not you must expect exceptions or fatal erros. + * + * It is also possible to derive the class and implement IteratorAggregate by + * downcasting the instances returned in getIterator. See the following + * example (assuming BaseClass implements Traversable): + \code + class SomeClass extends BaseClass implements IteratorAggregate + { + function getIterator() + { + return new IteratorIterator($this, 'BaseClass'); + } + } + \endcode + * + * As you can see in the example this approach requires that the class to + * downcast to is actually a base class of the specified iterator to wrap. + * Omitting the downcast in the above example would result in an endless loop + * since IteratorIterator::__construct() would call SomeClass::getIterator(). + */ +class IteratorIterator implements OuterIterator +{ + /** Construct an IteratorIterator from an Iterator or an IteratorAggregate. + * + * @param iterator inner iterator + * @param classname optional class the iterator has to be downcasted to + */ + function __construct(Traversable $iterator, $classname = null) + { + if ($iterator instanceof IteratorAggregate) + { + $iterator = $iterator->getIterator(); + } + if ($iterator instanceof Iterator) + { + $this->iterator = $iterator; + } + else + { + throw new Exception("Classes that only implement Traversable can be wrapped only after converting class IteratorIterator into c code"); + } + } + + /** \return the inner iterator as passed to the constructor + */ + function getInnerIterator() + { + return $this->iterator; + } + + /** \return whether the iterator is valid + */ + function valid() + { + return $this->iterator->valid(); + } + + /** \return current key + */ + function key() + { + return $this->iterator->key(); + } + + /** \return current value + */ + function current() + { + return $this->iterator->current(); + } + + /** forward to next element + */ + function next() + { + return $this->iterator->next(); + } + + /** rewind to the first element + */ + function rewind() + { + return $this->iterator->rewind(); + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->iterator, $func), $params); + } + + /** The inner iterator must be private because when this class will be + * converted to c code it won't no longer be available. + */ + private $iterator; +} + +?> diff --git a/ext/spl/internal/limititerator.inc b/ext/spl/internal/limititerator.inc new file mode 100644 index 0000000..c5bddea --- /dev/null +++ b/ext/spl/internal/limititerator.inc @@ -0,0 +1,134 @@ +<?php + +/** @file limititerator.inc + * @ingroup SPL + * @brief class LimitIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Limited Iteration over another Iterator + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.0 + * + * A class that starts iteration at a certain offset and only iterates over + * a specified amount of elements. + * + * This class uses SeekableIterator::seek() if available and rewind() plus + * a skip loop otehrwise. + */ +class LimitIterator implements OuterIterator +{ + private $it; + private $offset; + private $count; + private $pos; + + /** Construct + * + * @param it Iterator to limit + * @param offset Offset to first element + * @param count Maximum number of elements to show or -1 for all + */ + function __construct(Iterator $it, $offset = 0, $count = -1) + { + if ($offset < 0) { + throw new exception('Parameter offset must be > 0'); + } + if ($count < 0 && $count != -1) { + throw new exception('Parameter count must either be -1 or a value greater than or equal to 0'); + } + $this->it = $it; + $this->offset = $offset; + $this->count = $count; + $this->pos = 0; + } + + /** Seek to specified position + * @param position offset to seek to (relative to beginning not offset + * specified in constructor). + * @throw exception when position is invalid + */ + function seek($position) { + if ($position < $this->offset) { + throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset); + } + if ($position > $this->offset + $this->count && $this->count != -1) { + throw new exception('Cannot seek to '.$position.' which is behind offset '.$this->offset.' plus count '.$this->count); + } + if ($this->it instanceof SeekableIterator) { + $this->it->seek($position); + $this->pos = $position; + } else { + while($this->pos < $position && $this->it->valid()) { + $this->next(); + } + } + } + + /** Rewind to offset specified in constructor + */ + function rewind() + { + $this->it->rewind(); + $this->pos = 0; + $this->seek($this->offset); + } + + /** @return whether iterator is valid + */ + function valid() { + return ($this->count == -1 || $this->pos < $this->offset + $this->count) + && $this->it->valid(); + } + + /** @return current key + */ + function key() { + return $this->it->key(); + } + + /** @return current element + */ + function current() { + return $this->it->current(); + } + + /** Forward to nect element + */ + function next() { + $this->it->next(); + $this->pos++; + } + + /** @return current position relative to zero (not to offset specified in + * constructor). + */ + function getPosition() { + return $this->pos; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/multipleiterator.inc b/ext/spl/internal/multipleiterator.inc new file mode 100644 index 0000000..2ed71d5 --- /dev/null +++ b/ext/spl/internal/multipleiterator.inc @@ -0,0 +1,223 @@ +<?php +/** @file multipleiterator.inc + * @ingroup SPL + * @brief class MultipleIterator + * @author Johannes Schlueter + * @author Marcus Boerger + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator that iterates over several iterators one after the other + * @author Johannes Schlueter + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.3 + */ +class MultipleIterator implements Iterator +{ + /** Inner Iterators */ + private $iterators; + + /** Flags: const MIT_* */ + private $flags; + + /** do not require all sub iterators to be valid in iteration */ + const MIT_NEED_ANY = 0; + + /** require all sub iterators to be valid in iteration */ + const MIT_NEED_ALL = 1; + + /** keys are created from sub iterators position */ + const MIT_KEYS_NUMERIC = 0; + + /** keys are created from sub iterators associated infromation */ + const MIT_KEYS_ASSOC = 2; + + /** Construct a new empty MultipleIterator + * @param flags MIT_* flags + */ + public function __construct($flags = self::MIT_NEED_ALL|self::MIT_KEYS_NUMERIC) + { + $this->iterators = new SplObjectStorage(); + $this->flags = $flags; + } + + /** @return current flags MIT_* */ + public function getFlags() + { + return $this->flags; + } + + /** @param $flags new flags. */ + public function setFlags($flags) + { + $this->flags = $flags; + } + + /** @param $iter new Iterator to attach. + * @param $inf associative info forIteraotr, must be NULL, integer or string + * + * @throws IllegalValueException if a inf is none of NULL, integer or string + * @throws IllegalValueException if a inf is already an associated info + */ + public function attachIterator(Iterator $iter, $inf = NULL) + { + + if (!is_null($inf)) + { + if (!is_int($inf) && !is_string($inf)) + { + throw new IllegalValueException('Inf must be NULL, integer or string'); + } + foreach($this->iterators as $iter) + { + if ($inf == $this->iterators->getInfo()) + { + throw new IllegalValueException('Key duplication error'); + } + } + } + $this->iterators->attach($iter, $inf); + } + + /** @param $iter attached Iterator that should be detached. */ + public function detachIterator(Iterator $iter) + { + $this->iterators->detach($iter); + } + + /** @param $iter Iterator to check + * @return whether $iter is attached or not + */ + public function containsIterator(Iterator $iter) + { + return $this->iterator->contains($iter); + } + + /** @return number of attached Iterator instances. */ + public function countIterators() + { + return $this->iterators->count(); + } + + /** Rewind all attached Iterator instances. */ + public function rewind() + { + foreach($this->iterators as $iter) + { + $iter->rewind(); + } + } + + /** + * @return whether all or one sub iterator is valid depending on flags. + * In mode MIT_NEED_ALL we expect all sub iterators to be valid and + * return flase on the first non valid one. If that flag is not set we + * return true on the first valid sub iterator found. If no Iterator + * is attached, we always return false. + */ + public function valid() + { + if (!sizeof($this->iterators)) { + return false; + } + // The following code is an optimized version that executes as few + // valid() calls as necessary and that only checks the flags once. + $expect = $this->flags & self::MIT_NEED_ALL ? true : false; + foreach($this->iterators as $iter) + { + if ($expect != $iter->valid()) + { + return !$expect; + } + } + return $expect; + } + + /** Move all attached Iterator instances forward. That is invoke + * their next() method regardless of their state. + */ + public function next() + { + foreach($this->iterators as $iter) + { + $iter->next(); + } + } + + /** @return false if no sub Iterator is attached and an array of + * all registered Iterator instances current() result. + * @throws RuntimeException if mode MIT_NEED_ALL is set and at least one + * attached Iterator is not valid(). + * @throws IllegalValueException if a key is NULL and MIT_KEYS_ASSOC is set. + */ + public function current() + { + if (!sizeof($this->iterators)) + { + return false; + } + $retval = array(); + foreach($this->iterators as $iter) + { + if ($it->valid()) + { + if ($this->flags & self::MIT_KEYS_ASSOC) + { + $key = $this->iterators->getInfo(); + if (is_null($key)) + { + throw new IllegalValueException('Sub-Iterator is associated with NULL'); + } + $retval[$key] = $iter->current(); + } + else + { + $retval[] = $iter->current(); + } + } + else if ($this->flags & self::MIT_NEED_ALL) + { + throw new RuntimeException('Called current() with non valid sub iterator'); + } + else + { + $retval[] = NULL; + } + } + return $retval; + } + + /** @return false if no sub Iterator is attached and an array of + * all registered Iterator instances key() result. + * @throws LogicException if mode MIT_NEED_ALL is set and at least one + * attached Iterator is not valid(). + */ + public function key() + { + if (!sizeof($this->iterators)) + { + return false; + } + $retval = array(); + foreach($this->iterators as $iter) + { + if ($it->valid()) + { + $retval[] = $iter->key(); + } + else if ($this->flags & self::MIT_NEED_ALL) + { + throw new LogicException('Called key() with non valid sub iterator'); + } + else + { + $retval[] = NULL; + } + } + return $retval; + } +} diff --git a/ext/spl/internal/norewinditerator.inc b/ext/spl/internal/norewinditerator.inc new file mode 100644 index 0000000..8747a61 --- /dev/null +++ b/ext/spl/internal/norewinditerator.inc @@ -0,0 +1,28 @@ +<?php + +/** @file norewinditerator.inc + * @ingroup SPL + * @brief class NoRewindIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An Iterator wrapper that doesn't call rewind + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + */ +class NoRewindIterator extends IteratorIterator +{ + /** Simply prevent execution of inner iterators rewind(). + */ + function rewind() + { + // nothing to do + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/outeriterator.inc b/ext/spl/internal/outeriterator.inc new file mode 100644 index 0000000..f26d29d --- /dev/null +++ b/ext/spl/internal/outeriterator.inc @@ -0,0 +1,25 @@ +<?php + +/** @file outeriterator.inc + * @ingroup SPL + * @brief class OuterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Interface to access the current inner iteraor of iterator wrappers + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +interface OuterIterator extends Iterator +{ + /** @return inner iterator + */ + function getInnerIterator(); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/parentiterator.inc b/ext/spl/internal/parentiterator.inc new file mode 100644 index 0000000..cc377fc --- /dev/null +++ b/ext/spl/internal/parentiterator.inc @@ -0,0 +1,32 @@ +<?php + +/** @file parentiterator.inc + * @ingroup SPL + * @brief class FilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Iterator to filter parents + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.1 + * + * This extended FilterIterator allows a recursive iteration using + * RecursiveIteratorIterator that only shows those elements which have + * children. + */ +class ParentIterator extends RecursiveFilterIterator +{ + /** @return whetehr the current element has children + */ + function accept() + { + return $this->it->hasChildren(); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivearrayiterator.inc b/ext/spl/internal/recursivearrayiterator.inc new file mode 100644 index 0000000..a9450e1 --- /dev/null +++ b/ext/spl/internal/recursivearrayiterator.inc @@ -0,0 +1,59 @@ +<?php + +/** @file recursivearrayiterator.inc + * @ingroup Examples + * @brief class RecursiveArrayIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief A recursive array iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * Passes the RecursiveIterator interface to the inner Iterator and provides + * the same functionality as FilterIterator. This allows you to skip parents + * and all their childs before loading them all. You need to care about + * function getChildren() because it may not always suit your needs. The + * builtin behavior uses reflection to return a new instance of the exact same + * class it is called from. That is you extend RecursiveFilterIterator and + * getChildren() will create instance of that class. The problem is that doing + * this does not transport any state or control information of your accept() + * implementation to the new instance. To overcome this problem you might + * need to overwrite getChildren(), call this implementation and pass the + * control vaules manually. + */ +class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator +{ + /** @return whether the current element has children + */ + function hasChildren() + { + return is_array($this->current()); + } + + /** @return an iterator for the current elements children + * + * @note the returned iterator will be of the same class as $this + */ + function getChildren() + { + if ($this->current() instanceof self) + { + return $this->current(); + } + if (empty($this->ref)) + { + $this->ref = new ReflectionClass($this); + } + return $this->ref->newInstance($this->current()); + } + + private $ref; +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivecachingiterator.inc b/ext/spl/internal/recursivecachingiterator.inc new file mode 100644 index 0000000..0676d43 --- /dev/null +++ b/ext/spl/internal/recursivecachingiterator.inc @@ -0,0 +1,99 @@ +<?php + +/** @file recursivecachingiterator.inc + * @ingroup SPL + * @brief class RecursiveCachingIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Cached recursive iteration over another Iterator + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.1 + * + * @see CachingIterator + */ +class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator +{ + private $hasChildren; + private $getChildren; + + /** Construct from another iterator + * + * @param it Iterator to cache + * @param flags Bitmask: + * - CALL_TOSTRING (whether to call __toString() for every element) + * - CATCH_GET_CHILD (whether to catch exceptions when trying to get childs) + */ + function __construct(RecursiveIterator $it, $flags = self::CALL_TOSTRING) + { + parent::__construct($it, $flags); + } + + /** Rewind Iterator + */ + function rewind(); + { + $this->hasChildren = false; + $this->getChildren = NULL; + parent::rewind(); + } + + /** Forward to next element if necessary then an Iterator for the Children + * will be created. + */ + function next() + { + if ($this->hasChildren = $this->it->hasChildren()) + { + try + { + $child = $this->it->getChildren(); + if (!$this->ref) + { + $this->ref = new ReflectionClass($this); + } + $this->getChildren = $ref->newInstance($child, $this->flags); + } + catch(Exception $e) + { + if (!$this->flags & self::CATCH_GET_CHILD) + { + throw $e; + } + $this->hasChildren = false; + $this->getChildren = NULL; + } + } else + { + $this->getChildren = NULL; + } + parent::next(); + } + + private $ref; + + /** @return whether the current element has children + * @note The check whether the Iterator for the children can be created was + * already executed. Hence when flag CATCH_GET_CHILD was given in + * constructor this fucntion returns false so that getChildren does + * not try to access those children. + */ + function hasChildren() + { + return $this->hasChildren; + } + + /** @return An Iterator for the children + */ + function getChildren() + { + return $this->getChildren; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivefilteriterator.inc b/ext/spl/internal/recursivefilteriterator.inc new file mode 100644 index 0000000..b089919 --- /dev/null +++ b/ext/spl/internal/recursivefilteriterator.inc @@ -0,0 +1,62 @@ +<?php + +/** @file recursivefilteriterator.inc + * @ingroup SPL + * @brief class RecursiveFilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator to filter recursive iterators + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * Passes the RecursiveIterator interface to the inner Iterator and provides + * the same functionality as FilterIterator. This allows you to skip parents + * and all their childs before loading them all. You need to care about + * function getChildren() because it may not always suit your needs. The + * builtin behavior uses reflection to return a new instance of the exact same + * class it is called from. That is you extend RecursiveFilterIterator and + * getChildren() will create instance of that class. The problem is that doing + * this does not transport any state or control information of your accept() + * implementation to the new instance. To overcome this problem you might + * need to overwrite getChildren(), call this implementation and pass the + * control vaules manually. + */ +abstract class RecursiveFilterIterator extends FilterIterator implements RecursiveIterator +{ + /** @param $it the RecursiveIterator to filter + */ + function __construct(RecursiveIterator $it) + { + parent::__construct($it); + } + + /** @return whether the current element has children + */ + function hasChildren() + { + return $this->getInnerIterator()->hasChildren(); + } + + /** @return an iterator for the current elements children + * + * @note the returned iterator will be of the same class as $this + */ + function getChildren() + { + if (empty($this->ref)) + { + $this->ref = new ReflectionClass($this); + } + return $this->ref->newInstance($this->getInnerIterator()->getChildren()); + } + + private $ref; +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursiveiterator.inc b/ext/spl/internal/recursiveiterator.inc new file mode 100644 index 0000000..1eab3d6 --- /dev/null +++ b/ext/spl/internal/recursiveiterator.inc @@ -0,0 +1,30 @@ +<?php + +/** @file recursiveiterator.inc + * @ingroup SPL + * @brief class RecursiveIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Interface for recursive iteration with RecursiveIteratorIterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.0 + */ +interface RecursiveIterator extends Iterator +{ + /** @return whether the current element has children + */ + function hasChildren(); + + /** @return the sub iterator for the current element + * @note The returned object must implement RecursiveIterator. + */ + function getChildren(); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursiveiteratoriterator.inc b/ext/spl/internal/recursiveiteratoriterator.inc new file mode 100644 index 0000000..35fa801 --- /dev/null +++ b/ext/spl/internal/recursiveiteratoriterator.inc @@ -0,0 +1,237 @@ +<?php + +/** @file recursiveiteratoriterator.inc + * @ingroup SPL + * @brief class RecursiveIteratorIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Iterates through recursive iterators + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.0 + * + * The objects of this class are created by instances of RecursiveIterator. + * Elements of those iterators may be traversable themselves. If so these + * sub elements are recursed into. + */ +class RecursiveIteratorIterator implements OuterIterator +{ + /** Mode: Only show leaves */ + const LEAVES_ONLY = 0; + /** Mode: Show parents prior to their children */ + const SELF_FIRST = 1; + /** Mode: Show all children prior to their parent */ + const CHILD_FIRST = 2; + + /** Flag: Catches exceptions during getChildren() calls and simply jumps + * to the next element. */ + const CATCH_GET_CHILD = 0x00000002; + + private $ait = array(); + private $count = 0; + private $mode = self::LEAVES_ONLY; + private $flags = 0; + + /** Construct from RecursiveIterator + * + * @param it RecursiveIterator to iterate + * @param mode Operation mode (one of): + * - LEAVES_ONLY only show leaves + * - SELF_FIRST show parents prior to their childs + * - CHILD_FIRST show all children prior to their parent + * @param flags Control flags, zero or any combination of the following + * (since PHP 5.1). + * - CATCH_GET_CHILD which catches exceptions during + * getChildren() calls and simply jumps to the next + * element. + */ + function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0) + { + $this->ait[0] = $it; + $this->mode = $mode; + $this->flags = $flags; + } + + /** Rewind to top iterator as set in constructor + */ + function rewind() + { + while ($this->count) { + unset($this->ait[$this->count--]); + $this->endChildren(); + } + $this->ait[0]->rewind(); + $this->ait[0]->recursed = false; + callNextElement(true); + } + + /** @return whether iterator is valid + */ + function valid() + { + $count = $this->count; + while ($count) { + $it = $this->ait[$count]; + if ($it->valid()) { + return true; + } + $count--; + $this->endChildren(); + } + return false; + } + + /** @return current key + */ + function key() + { + $it = $this->ait[$this->count]; + return $it->key(); + } + + /** @return current element + */ + function current() + { + $it = $this->ait[$this->count]; + return $it->current(); + } + + /** Forward to next element + */ + function next() + { + while ($this->count) { + $it = $this->ait[$this->count]; + if ($it->valid()) { + if (!$it->recursed && callHasChildren()) { + $it->recursed = true; + try + { + $sub = callGetChildren(); + } + catch (Exception $e) + { + if (!($this->flags & self::CATCH_GET_CHILD)) + { + throw $e; + } + $it->next(); + continue; + } + $sub->recursed = false; + $sub->rewind(); + if ($sub->valid()) { + $this->ait[++$this->count] = $sub; + if (!$sub instanceof RecursiveIterator) { + throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator'); + } + $this->beginChildren(); + return; + } + unset($sub); + } + $it->next(); + $it->recursed = false; + if ($it->valid()) { + return; + } + $it->recursed = false; + } + if ($this->count) { + unset($this->ait[$this->count--]); + $it = $this->ait[$this->count]; + $this->endChildren(); + callNextElement(false); + } + } + callNextElement(true); + } + + /** @return Sub Iterator at given level or if unspecified the current sub + * Iterator + */ + function getSubIterator($level = NULL) + { + if (is_null($level)) { + $level = $this->count; + } + return @$this->ait[$level]; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** @return Current Depth (Number of parents) + */ + function getDepth() + { + return $this->level; + } + + /** @return whether current sub iterators current element has children + * @since PHP 5.1 + */ + function callHasChildren() + { + return $this->ait[$this->count]->hasChildren(); + } + + /** @return current sub iterators current children + * @since PHP 5.1 + */ + function callGetChildren() + { + return $this->ait[$this->count]->getChildren(); + } + + /** Called right after calling getChildren() and its rewind(). + * @since PHP 5.1 + */ + function beginChildren() + { + } + + /** Called after current child iterator is invalid and right before it + * gets destructed. + * @since PHP 5.1 + */ + function endChildren() + { + } + + private function callNextElement($after_move) + { + if ($this->valid()) + { + if ($after_move) + { + if (($this->mode == self::SELF_FIRST && $this->callHasChildren()) + || $this->mode == self::LEAVES_ONLY) + $this->nextElement(); + } + else + { + $this->nextElement(); + } + } + } + + /** Called when the next element is available + */ + function nextElement() + { + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursiveregexiterator.inc b/ext/spl/internal/recursiveregexiterator.inc new file mode 100644 index 0000000..ffcff0c --- /dev/null +++ b/ext/spl/internal/recursiveregexiterator.inc @@ -0,0 +1,61 @@ +<?php + +/** @file recursiveregexiterator.inc + * @ingroup SPL + * @brief class RegexIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Recursive regular expression filter for iterators + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * This filter iterator assumes that the inner iterator + */ +class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator +{ + /** + * Constructs a regular expression filter around an iterator whose + * elemnts or keys are strings. + * + * @param it inner iterator + * @param regex the regular expression to match + * @param mode operation mode (one of self::MATCH, self::GET_MATCH, + * self::ALL_MATCHES, self::SPLIT) + * @param flags special flags (self::USE_KEY) + * @param preg_flags global PREG_* flags, see preg_match(), + * preg_match_all(), preg_split() + */ + function __construct(RecursiveIterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) { + parent::__construct($it, $regex, $mode, $flags, $preg_flags); + } + + /** @return whether the current element has children + */ + function hasChildren() + { + return $this->getInnerIterator()->hasChildren(); + } + + /** @return an iterator for the current elements children + * + * @note the returned iterator will be of the same class as $this + */ + function getChildren() + { + if (empty($this->ref)) + { + $this->ref = new ReflectionClass($this); + } + return $this->ref->newInstance($this->getInnerIterator()->getChildren()); + } + + private $ref; +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivetreeiterator.inc b/ext/spl/internal/recursivetreeiterator.inc new file mode 100644 index 0000000..dfcdc05 --- /dev/null +++ b/ext/spl/internal/recursivetreeiterator.inc @@ -0,0 +1,132 @@ +<?php + +/** @file recursivetreeiterator.inc + * @ingroup SPL + * @brief class RecursiveTreeIterator + * @author Marcus Boerger, Johannes Schlueter + * @date 2005 - 2009 + * + * SPL - Standard PHP Library + */ + + +/** @ingroup SPL + * @brief RecursiveIteratorIterator to generate ASCII graphic trees for the + * entries in a RecursiveIterator + * @author Marcus Boerger, Johannes Schlueter + * @version 1.1 + * @since PHP 5.3 + */ +class RecursiveTreeIterator extends RecursiveIteratorIterator +{ + const BYPASS_CURRENT = 0x00000004; + const BYPASS_KEY = 0x00000008; + + private $rit_flags; + + /** + * @param it iterator to use as inner iterator + * @param rit_flags flags passed to RecursiveIteratoIterator (parent) + * @param cit_flags flags passed to RecursiveCachingIterator (for hasNext) + * @param mode mode passed to RecursiveIteratoIterator (parent) + */ + function __construct(RecursiveIterator $it, $rit_flags = self::BYPASS_KEY, $cit_flags = CachingIterator::CATCH_GET_CHILD, $mode = self::SELF_FIRST) + { + parent::__construct(new RecursiveCachingIterator($it, $cit_flags), $mode, $rit_flags); + $this->rit_flags = $rit_flags; + } + + private $prefix = array(0=>'', 1=>'| ', 2=>' ', 3=>'|-', 4=>'\-', 5=>''); + + /** Prefix used to start elements. */ + const PREFIX_LEFT = 0; + /** Prefix used if $level < depth and hasNext($level) == true. */ + const PREFIX_MID_HAS_NEXT = 1; + /** Prefix used if $level < depth and hasNext($level) == false. */ + const PREFIX_MID_LAST = 2; + /** Prefix used if $level == depth and hasNext($level) == true. */ + const PREFIX_END_HAS_NEXT = 3; + /** Prefix used if $level == depth and hasNext($level) == false. */ + const PREFIX_END_LAST = 4; + /** Prefix used right in front of the current element. */ + const PREFIX_RIGHT = 5; + + /** + * Set prefix part as used in getPrefix() and stored in $prefix. + * @param $part any PREFIX_* const. + * @param $value new prefix string for specified part. + * @throws OutOfRangeException if 0 > $part or $part > 5. + */ + function setPrefixPart($part, $value) + { + if (0 > $part || $part > 5) { + throw new OutOfRangeException(); + } + $this->prefix[$part] = (string)$value; + } + + /** @return string to place in front of current element + */ + function getPrefix() + { + $tree = ''; + for ($level = 0; $level < $this->getDepth(); $level++) + { + $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[1] : $this->prefix[2]; + } + $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[3] : $this->prefix[4]; + + return $this->prefix[0] . $tree . $this->prefix[5]; + } + + /** @return string presentation build for current element + */ + function getEntry() + { + return @(string)parent::current(); + } + + /** @return string to place after the current element + */ + function getPostfix() + { + return ''; + } + + /** @return the current element prefixed and postfixed + */ + function current() + { + if ($this->rit_flags & self::BYPASS_CURRENT) + { + return parent::current(); + } + else + { + return $this->getPrefix() . $this->getEntry() . $this->getPostfix(); + } + } + + /** @return the current key prefixed and postfixed + */ + function key() + { + if ($this->rit_flags & self::BYPASS_KEY) + { + return parent::key(); + } + else + { + return $this->getPrefix() . parent::key() . $this->getPostfix(); + } + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getSubIterator(), $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/regexiterator.inc b/ext/spl/internal/regexiterator.inc new file mode 100644 index 0000000..c6addb9 --- /dev/null +++ b/ext/spl/internal/regexiterator.inc @@ -0,0 +1,170 @@ +<?php + +/** @file regexiterator.inc + * @ingroup SPL + * @brief class RegexIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Regular expression filter for iterators + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * This filter iterator assumes that the inner iterator + */ +class RegexIterator extends FilterIterator +{ + const USE_KEY = 0x00000001; /**< If present in $flags the key is + used rather then the current value. */ + + const MATCH = 0; /**< Mode: Executed a plain match only */ + const GET_MATCH = 1; /**< Mode: Return the first matche (if any) */ + const ALL_MATCHES = 2; /**< Mode: Return all matches (if any) */ + const SPLIT = 3; /**< Mode: Return the split values (if any) */ + const REPLACE = 4; /**< Mode: Replace the input key or current */ + + private $regex; /**< the regular expression to match against */ + private $mode; /**< operation mode (one of self::MATCH, + self::GET_MATCH, self::ALL_MATCHES, self::SPLIT) */ + private $flags; /**< special flags (self::USE_KEY) */ + private $preg_flags;/**< PREG_* flags, see preg_match(), preg_match_all(), + preg_split() */ + private $key; /**< the value used for key() */ + private $current; /**< the value used for current() */ + + /** + * Constructs a regular expression filter around an iterator whose + * elemnts or keys are strings. + * + * @param it inner iterator + * @param regex the regular expression to match + * @param mode operation mode (one of self::MATCH, self::GET_MATCH, + * self::ALL_MATCHES, self::SPLIT) + * @param flags special flags (self::USE_KEY) + * @param preg_flags global PREG_* flags, see preg_match(), + * preg_match_all(), preg_split() + */ + function __construct(Iterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) { + parent::__construct($it); + $this->regex = $regex; + $this->flags = $flags; + $this->mode = $mode; + $this->preg_flags = $preg_flags; + } + + /** + * Match current or key against regular expression using mode, flags and + * preg_flags. + * + * @return whether this is a match + * + * @warning never call this twice for the same state + */ + function accept() + { + $matches = array(); + $this->key = parent::key(); + $this->current = parent::current(); + /* note that we use $this->current, rather than calling parent::current() */ + $subject = ($this->flags & self::USE_KEY) ? $this->key : $this->current; + switch($this->mode) + { + case self::MATCH: + return preg_match($this->regex, $subject, $matches, $this->preg_flags); + + case self::GET_MATCH: + $this->current = array(); + return preg_match($this->regex, $subject, $this->current, $this->preg_flags) > 0; + + case self::ALL_MATCHES: + $this->current = array(); + return preg_match_all($this->regex, $subject, $this->current, $this->preg_flags) > 0; + + case self::SPLIT: + $this->current = array(); + preg_split($this->regex, $subject, $this->current, $this->preg_flags) > 1; + + case self::REPLACE: + $this->current = array(); + $result = preg_replace($this->regex, $this->replacement, $subject); + if ($this->flags & self::USE_KEY) + { + $this->key = $result; + } + else + { + $this->current = $result; + } + } + } + + /** @return the key after accept has been called + */ + function key() + { + return $this->key; + } + + /** @return the current value after accept has been called + */ + function current() + { + return $this->current; + } + + /** @return current operation mode + */ + function getMode() + { + return $this->mode; + } + + /** @param mode new operaion mode + */ + function setMode($mode) + { + $this->mode = $mode; + } + + /** @return current operation flags + */ + function getFlags() + { + return $this->flags; + } + + /** @param flags new operaion flags + */ + function setFlags($flags) + { + $this->flags = $flags; + } + + /** @return current PREG flags + */ + function getPregFlags() + { + return $this->preg_flags; + } + + /** @param preg_flags new PREG flags + */ + function setPregFlags($preg_flags) + { + $this->preg_flags = $preg_flags; + } + + /** @return current regular expression + */ + function getRegex() + { + return $this->regex; + } +} + +?> diff --git a/ext/spl/internal/seekableiterator.inc b/ext/spl/internal/seekableiterator.inc new file mode 100644 index 0000000..b4f66bd --- /dev/null +++ b/ext/spl/internal/seekableiterator.inc @@ -0,0 +1,48 @@ +<?php + +/** @file seekableiterator.inc + * @ingroup SPL + * @brief class SeekableIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @brief seekable iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.0 + * + * Turns a normal iterator ino a seekable iterator. When there is a way + * to seek on an iterator LimitIterator can use this to efficiently rewind + * to offset. + */ +interface SeekableIterator extends Iterator +{ + /** Seek to an absolute position + * + * \param $index position to seek to + * \return void + * + * The method should throw an exception if it is not possible to seek to + * the given position. Typically this exception should be of type + * OutOfBoundsException. + \code + function seek($index); + $this->rewind(); + $position = 0; + while($position < $index && $this->valid()) { + $this->next(); + $position++; + } + if (!$this->valid()) { + throw new OutOfBoundsException('Invalid seek position'); + } + } + \endcode + */ + function seek($index); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/spldoublylinkedlist.inc b/ext/spl/internal/spldoublylinkedlist.inc new file mode 100644 index 0000000..e87e4b1 --- /dev/null +++ b/ext/spl/internal/spldoublylinkedlist.inc @@ -0,0 +1,277 @@ +<?php +/** @file spldoublylinkedlist.inc + * @ingroup SPL + * @brief class SplDoublyLinkedList + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Doubly Linked List + * @since PHP 5.3 + * + * The SplDoublyLinkedList class provides the main functionalities of a + * doubly linked list (DLL). + * @note The following userland implementation of Iterator is a bit different + * from the internal one. Internally, iterators generated by nested + * foreachs are independent, while they share the same traverse pointer + * in userland. + */ +class SplDoublyLinkedList implements Iterator, ArrayAccess, Countable +{ + protected $_llist = array(); + protected $_it_mode = 0; + protected $_it_pos = 0; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_LIFO = 0x00000002; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_FIFO = 0x00000000; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_KEEP = 0x00000000; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_DELETE = 0x00000001; + + /** @return the element popped from the end of the DLL. + * @throw RuntimeException If the datastructure is empty. + */ + public function pop() + { + if (count($this->_llist) == 0) { + throw new RuntimeException("Can't pop from an empty datastructure"); + } + return array_pop($this->_llist); + } + + /** @return the element shifted from the beginning of the DLL. + * @throw RuntimeException If the datastructure is empty. + */ + public function shift() + { + if (count($this->_llist) == 0) { + throw new RuntimeException("Can't shift from an empty datastructure"); + } + return array_shift($this->_llist); + } + + /** Pushes an element to the end of the DLL. + * @param $data variable to add to the DLL. + */ + public function push($data) + { + array_push($this->_llist, $data); + return true; + } + + /** Adds an element to the beginning of the DLL. + * @param $data variable to add to the DLL. + */ + public function unshift($data) + { + array_unshift($this->_llist, $data); + return true; + } + + /** @return the element at the beginning of the DLL. + */ + public function top() + { + return end($this->_llist); + } + + /** @return the element at the end of the DLL. + */ + public function bottom() + { + return reset($this->_llist); + } + + /** @return number elements in the DLL. + */ + public function count() + { + return count($this->_llist); + } + + /** @return whether the DLL is empty. + */ + public function isEmpty() + { + return ($this->count() == 0); + } + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * - The direction of the iteration (either one or the other) + * - SplDoublyLnkedList::IT_MODE_LIFO (Stack style) + * - SplDoublyLnkedList::IT_MODE_FIFO (Queue style) + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_FIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @param $mode new mode of iteration + */ + public function setIteratorMode($mode) + { + $this->_it_mode = $mode; + } + + /** @return the current iteration mode + * @see setIteratorMode + */ + public function getIteratorMode() + { + return $this->_it_mode; + } + + /** Rewind to top iterator as set in constructor + */ + public function rewind() + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $this->_it_pos = count($this->_llist)-1; + } else { + $this->_it_pos = 0; + } + } + + /** @return whether iterator is valid + */ + public function valid() + { + return array_key_exists($this->_it_pos, $this->_llist); + } + + /** @return current key + */ + public function key() + { + return $this->_it_pos; + } + + /** @return current object + */ + public function current() + { + return $this->_llist[$this->_it_pos]; + } + + /** Forward to next element + */ + public function next() + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + if ($this->_it_mode & self::IT_MODE_DELETE) { + $this->pop(); + } + $this->_it_pos--; + } else { + if ($this->_it_mode & self::IT_MODE_DELETE) { + $this->shift(); + } else { + $this->_it_pos++; + } + } + } + + /** @return whether a certain offset exists in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetExists($offset) + { + if (!is_numeric($offset)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + return array_key_exists($offset, $this->_llist); + } + } + + /** @return the data at a certain offset in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetGet($offset) + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + return $this->_llist[$realOffset]; + } + } + + /** Defines the data at a certain offset in the DLL + * + * @param $offset The offset + * @param $value New value + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetSet($offset, $value) + { + if ($offset === null) { + return $this->push($value); + } + + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + $this->_llist[$realOffset] = $value; + } + } + + /** Unsets the element at a certain offset in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetUnset($offset) + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + array_splice($this->_llist, $realOffset, 1); + } + } +} + +?> diff --git a/ext/spl/internal/splfileobject.inc b/ext/spl/internal/splfileobject.inc new file mode 100644 index 0000000..46b941f --- /dev/null +++ b/ext/spl/internal/splfileobject.inc @@ -0,0 +1,377 @@ +<?php + +/** @file splfileobject.inc + * @ingroup SPL + * @brief class FileObject + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Object representation for any stream + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + */ +class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator +{ + /** Flag: wheter to suppress new lines */ + const DROP_NEW_LINE = 0x00000001; + + private $fp; + private $fname; + private $line = NULL; + private $lnum = 0; + private $max_len = 0; + private $flags = 0; + private $delimiter= ','; + private $enclosure= '"'; + + /** + * Constructs a new file object + * + * @param $file_name The name of the stream to open + * @param $open_mode The file open mode + * @param $use_include_path Whether to search in include paths + * @param $context A stream context + * @throw RuntimeException If file cannot be opened (e.g. insufficient + * access rights). + */ + function __construct($file_name, $open_mode = 'r', $use_include_path = false, $context = NULL) + { + $this->fp = fopen($file_name, $open_mode, $use_include_path, $context); + if (!$this->fp) + { + throw new RuntimeException("Cannot open file $file_name"); + } + $this->fname = $file_name; + } + + /** + * @return whether the end of the stream is reached + */ + function eof() + { + return eof($this->fp); + } + + /** increase current line number + * @return next line from stream + */ + function fgets() + { + $this->freeLine(); + $this->lnum++; + $buf = fgets($this->fp, $this->max_len); + + return $buf; + } + + /** + * @param delimiter character used as field separator + * @param enclosure end of + * @return array containing read data + */ + function fgetcsv($delimiter = NULL, $enclosure = NULL) + { + $this->freeLine(); + $this->lnum++; + switch(fun_num_args()) + { + case 0: + $delimiter = $this->delimiter; + case 1: + $enclosure = $this->enclosure; + default: + case 2: + break; + } + return fgetcsv($this->fp, $this->max_len, $delimiter, $enclosure); + } + + /** + * Set the delimiter and enclosure character used in fgetcsv + * + * @param delimiter new delimiter, defaults to ',' + * @param enclosure new enclosure, defaults to '"' + */ + function setCsvControl($delimiter = ';', $enclosure = '"') + { + $this->delimiter = $delimiter; + $this->enclosure = $enclosure; + } + + /** + * @return array(delimiter, enclosure) as used in fgetcsv + */ + function getCsvControl($delimiter = ',', $enclosure = '"') + { + return array($this->delimiter, $this->enclosure); + } + + /** + * @param operation lock operation (LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB) + * @retval $wouldblock whether the operation would block + */ + function flock($operation, &$wouldblock) + { + return flock($this->fp, $operation, $wouldblock); + } + + /** + * Flush current data + * @return success or failure + */ + function fflush() + { + return fflush($this->fp); + } + + /** + * @return current file position + */ + function ftell() + { + return ftell($this->fp); + } + + /** + * @param pos new file position + * @param whence seek method (SEEK_SET, SEEK_CUR, SEEK_END) + * @return Upon success, returns 0; otherwise, returns -1. Note that + * seeking past EOF is not considered an error. + */ + function fseek($pos, $whence = SEEK_SET) + { + return fseek($this->fp, $pos, $whence); + } + + /** + * @return next char from file + * @note a new line character does not increase $this->lnum + */ + function fgetc() + { + $this->freeLine(); + $c = fgetc($this->fp); + if ($c == '\n') { + $this->lnum++; + } + } + + /** Read and return remaining part of stream + * @return size of remaining part passed through + */ + function fpassthru() + { + return fpassthru($this->fp); + } + + /** Get a line from the file and strip HTML tags + * @param $allowable_tags tags to keep in the string + */ + function fgetss($allowable_tags = NULL) + { + return fgetss($this->fp, $allowable_tags); + } + + /** Scan the next line + * @param $format string specifying format to parse + */ + function fscanf($format /* , ... */) + { + $this->freeLine(); + $this->lnum++; + return fscanf($this->fp, $format /* , ... */); + } + + /** + * @param $str to write + * @param $length maximum line length to write + */ + function fwrite($str, $length = NULL) + { + return fwrite($this->fp, $length); + } + + /** + * @return array of file stat information + */ + function fstat() + { + return fstat($this->fp); + } + + /** + * @param $size new size to truncate file to + */ + function ftruncate($size) + { + return ftruncate($this->fp, $size); + } + + /** + * @param $flags new flag set + */ + function setFlags($flags) + { + $this->flags = $flags; + } + + /** + * @return current set of flags + */ + function getFlags() + { + return $this->flags; + } + + /** + * @param $max_len set the maximum line length read + */ + function setMaxLineLen($max_len) + { + $this->max_len = $max_len; + } + + /** + * @return current setting for max line + */ + function getMaxLineLen() + { + return $this->max_len; + } + + /** + * @return false + */ + function hasChildren() + { + return false; + } + + /** + * @return false + */ + function getChildren() + { + return NULL; + } + + /** + * Invalidate current line buffer and set line number to 0. + */ + function rewind() + { + $this->freeLine(); + $this->lnum = 0; + } + + /** + * @return whether more data can be read + */ + function valid() + { + return !$this->eof(); + } + + /** + * @note Fill current line buffer if not done yet. + * @return line buffer + */ + function current() + { + if (is_null($this->line)) + { + $this->line = getCurrentLine(); + } + return $this->line; + } + + /** + * @return line number + * @note fgetc() will increase the line number when reaing a new line char. + * This has the effect key() called on a read a new line will already + * return the increased line number. + * @note Line counting works as long as you only read the file and do not + * use fseek(). + */ + function key() + { + return $this->lnum; + } + + /** Invalidate current line buffer. + */ + function next() + { + $this->freeLine(); + } + + /** + * @return next line read from file and increase the line counter + */ + private function readLine() + { + if ($this->eof()) + { + $this->freeLine(); + throw new RuntimeException("Cannot read from file " . $this->fname); + } + if ($this->line) { + $this->lnum++; + } + $this->freeLine(); + $this->line = fgets($this->fp, $this->max_len); + return $this->line; + } + + /** + * Free the current line buffer and increment the line counter + */ + private function freeLine() + { + if ($this->line) { + $this->line = NULL; + } + } + + /* + * @note If you DO overload this function key() and current() will increment + * $this->lnum automatically. If not then function reaLine() will do + * that for you. + */ + function getCurrentLine() + { + $this->freeLine(); + if ($this->eof()) + { + throw new RuntimeException("Cannot read from file " . $this->fname); + } + $this->readLine(); + } + + /** + * @return current line + */ + function __toString() + { + return current(); + } + + /** + * @param $line_pos Seek to this line + */ + function seek($line_pos) + { + $this->rewind(); + while($this->lnum < $line_pos && !$this->eof()) + { + $this->getCurrentLine(); + } + } +} + +?> diff --git a/ext/spl/internal/splobjectstorage.inc b/ext/spl/internal/splobjectstorage.inc new file mode 100644 index 0000000..fa16406 --- /dev/null +++ b/ext/spl/internal/splobjectstorage.inc @@ -0,0 +1,188 @@ +<?php + +/** @file splobjectstorage.inc + * @ingroup SPL + * @brief class SplObjectStorage + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Object storage + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1.2 + * + * 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, ArrayAccess +{ + 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() + { + $element = current($this->storage); + return $element ? $element[0] : NULL + } + + /** @return get current object's associated information + * @since 5.3.0 + */ + function getInfo() + { + $element = current($this->storage); + return $element ? $element[1] : NULL + } + + /** @return set current object's associated information + * @since 5.3.0 + */ + function setInfo($inf = NULL) + { + if ($this->valid()) { + $this->storage[$this->index][1] = $inf; + } + } + + /** Forward to next element + */ + function next() + { + next($this->storage); + $this->index++; + } + + /** @return number of objects in storage + */ + function count() + { + return count($this->storage); + } + + /** @param $obj object to look for + * @return whether $obj is contained in storage + */ + function contains($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $element) + { + if ($object === $element[0]) + { + return true; + } + } + } + return false; + } + + /** @param $obj new object to attach to storage or object whose + * associative information is to be replaced + * @param $inf associative information stored along the object + */ + function attach($obj, $inf = NULL) + { + if (is_object($obj) && !$this->contains($obj)) + { + $this->storage[] = array($obj, $inf); + } + } + + /** @param $obj object to remove from storage + */ + function detach($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $idx => $element) + { + if ($object === $element[0]) + { + unset($this->storage[$idx]); + $this->rewind(); + return; + } + } + } + } + + /** @param $obj new object to attach to storage or object whose + * associative information is to be replaced + * @param $inf associative information stored along the object + * @since 5.3.0 + */ + function offsetSet($obj, $inf) + { + $this->attach($obj, $inf); + } + + /** @param $obj Exising object to look for + * @return associative information stored with object + * @throw UnexpectedValueException if Object $obj is not contained in + * storage + * @since 5.3.0 + */ + function offsetGet($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $idx => $element) + { + if ($object === $element[0]) + { + return $element[1]; + } + } + } + throw new UnexpectedValueException('Object not found'); + } + + /** @param $obj Exising object to look for + * @return associative information stored with object + * @since 5.3.0 + */ + function offsetUnset($obj) + { + $this->detach($obj); + } + + /** @param $obj object to look for + * @return whether $obj is contained in storage + */ + function offsetEsists($obj) + { + return $this->contains($obj); + } +} + +?> diff --git a/ext/spl/internal/splqueue.inc b/ext/spl/internal/splqueue.inc new file mode 100644 index 0000000..368a259 --- /dev/null +++ b/ext/spl/internal/splqueue.inc @@ -0,0 +1,71 @@ +<?php + +/** @file splqueue.inc + * @ingroup SPL + * @brief class SplQueue + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Implementation of a Queue through a DoublyLinkedList. As SplQueue + * extends SplDoublyLinkedList, unshift() and pop() are still available + * even though they don't make much sense for a queue. For convenience, + * two aliases are available: + * - enqueue() is an alias of push() + * - dequeue() is an alias of shift() + * + * @since PHP 5.3 + * + * The SplQueue class provides the main functionalities of a + * queue implemented using a doubly linked list (DLL). + */ +class SplQueue extends SplDoublyLinkedList +{ + protected $_it_mode = parent::IT_MODE_FIFO; + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @note The iteration's direction is not modifiable for queue instances + * @param $mode New mode of iteration + * @throw RuntimeException If the new mode affects the iteration's direction. + */ + public function setIteratorMode($mode) + { + if ($mode & parent::IT_MODE_LIFO === parent::IT_MODE_LIFO) { + throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen"); + } + + $this->_it_mode = $mode; + } + + /** @return the first element of the queue. + * @note dequeue is an alias of push() + * @see splDoublyLinkedList::push() + */ + public function dequeue() + { + return parent::shift(); + } + + /** Pushes an element at the end of the queue. + * @param $data variable to add to the queue. + * @note enqueue is an alias of shift() + * @see splDoublyLinkedList::shift() + */ + public function enqueue($data) + { + return parent::push($data); + } +} + +?> diff --git a/ext/spl/internal/splstack.inc b/ext/spl/internal/splstack.inc new file mode 100644 index 0000000..70b1443 --- /dev/null +++ b/ext/spl/internal/splstack.inc @@ -0,0 +1,48 @@ +<?php + +/** @file splstack.inc + * @ingroup SPL + * @brief class SplStack + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Implementation of a stack through a DoublyLinkedList. As SplStack + * extends SplDoublyLinkedList, shift() and unshift() are still available even + * though they don't make much sense for a stack. + * @since PHP 5.3 + * + * The SplStack class provides the main functionalities of a + * stack implemented using a doubly linked list (DLL). + */ +class SplStack extends SplDoublyLinkedList +{ + protected $_it_mode = parent::IT_MODE_LIFO; + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @note The iteration's direction is not modifiable for stack instances + * @param $mode New mode of iteration + * @throw RuntimeException If the new mode affects the iteration's direction. + */ + public function setIteratorMode($mode) + { + if ($mode & parent::IT_MODE_LIFO !== parent::IT_MODE_LIFO) { + throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen"); + } + + $this->_it_mode = $mode; + } +} + +?> |