|
|
|
@ -1,5 +1,4 @@ |
|
|
|
<?php |
|
|
|
|
|
|
|
/** @file spldoublylinkedlist.inc |
|
|
|
* @ingroup SPL |
|
|
|
* @brief class SplDoublyLinkedList |
|
|
|
@ -13,23 +12,29 @@ |
|
|
|
* @brief Doubly Linked List |
|
|
|
* @since PHP 5.3 |
|
|
|
* |
|
|
|
* The SplDoublyLinkedList class provides the main functionnalities of a |
|
|
|
* 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 independant, while they share the same traverse pointer |
|
|
|
* in userland. |
|
|
|
*/ |
|
|
|
class SplDoublyLinkedList implements Traversable, ArrayAccess, Countable |
|
|
|
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 = 0x00000001; |
|
|
|
const IT_MODE_LIFO = 0x00000002; |
|
|
|
|
|
|
|
/** Iterator mode |
|
|
|
* @see setIteratorMode |
|
|
|
*/ |
|
|
|
const IT_MODE_FIFO = 0x00000000; |
|
|
|
|
|
|
|
|
|
|
|
/** Iterator mode |
|
|
|
* @see setIteratorMode |
|
|
|
*/ |
|
|
|
@ -38,41 +43,75 @@ class SplDoublyLinkedList implements Traversable, ArrayAccess, Countable |
|
|
|
/** Iterator mode |
|
|
|
* @see setIteratorMode |
|
|
|
*/ |
|
|
|
const IT_MODE_DELETE = 0x00000002; |
|
|
|
const IT_MODE_DELETE = 0x00000001; |
|
|
|
|
|
|
|
/** @return the element popped from the end of the DLL. |
|
|
|
* @throw RuntimeException If the datastructure is empty. |
|
|
|
*/ |
|
|
|
function pop() {/**/} |
|
|
|
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. |
|
|
|
*/ |
|
|
|
function shift() {/**/} |
|
|
|
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. |
|
|
|
*/ |
|
|
|
function push($data) {/**/} |
|
|
|
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. |
|
|
|
*/ |
|
|
|
function unshift($data) {/**/} |
|
|
|
public function unshift($data) |
|
|
|
{ |
|
|
|
array_unshift($this->_llist, $data); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/** @return the element at the beginning of the DLL. |
|
|
|
*/ |
|
|
|
function top() {/**/} |
|
|
|
public function top() |
|
|
|
{ |
|
|
|
return end($this->_llist); |
|
|
|
} |
|
|
|
|
|
|
|
/** @return the element at the end of the DLL. |
|
|
|
*/ |
|
|
|
function bottom() {/**/} |
|
|
|
public function bottom() |
|
|
|
{ |
|
|
|
return reset($this->_llist); |
|
|
|
} |
|
|
|
|
|
|
|
/** @return number elements in the DLL. |
|
|
|
*/ |
|
|
|
function count() {/**/} |
|
|
|
public function count() |
|
|
|
{ |
|
|
|
return count($this->_llist); |
|
|
|
} |
|
|
|
|
|
|
|
/** @return whether the DLL is empty. |
|
|
|
*/ |
|
|
|
function isEmpty() {/**/} |
|
|
|
public function isEmpty() |
|
|
|
{ |
|
|
|
return ($this->count() == 0); |
|
|
|
} |
|
|
|
|
|
|
|
/** Changes the iteration mode. There are two orthogonal sets of modes that |
|
|
|
* can be set: |
|
|
|
@ -88,13 +127,151 @@ class SplDoublyLinkedList implements Traversable, ArrayAccess, Countable |
|
|
|
* |
|
|
|
* @param $mode new mode of iteration |
|
|
|
*/ |
|
|
|
function setIteratorMode($mode) {/**/} |
|
|
|
public function setIteratorMode($mode) |
|
|
|
{ |
|
|
|
$this->_it_mode = $mode; |
|
|
|
} |
|
|
|
|
|
|
|
/** @return the current iteration mode |
|
|
|
* @see setIteratorMode |
|
|
|
*/ |
|
|
|
function getIteratorMode() {/**/} |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
?> |