_iterator = $iterator; $this->_bufferSize = max($bufferSize, 1); $this->_buffer = new \SplDoublyLinkedList(); return; } /** * Get inner iterator. * * @return \Iterator */ public function getInnerIterator() { return $this->_iterator; } /** * Get buffer. * * @return \SplDoublyLinkedList */ protected function getBuffer() { return $this->_buffer; } /** * Get buffer size. * * @return int */ public function getBufferSize() { return $this->_bufferSize; } /** * Return the current element. * * @return mixed */ public function current() { return $this->getBuffer()->current()[self::BUFFER_VALUE]; } /** * Return the key of the current element. * * @return mixed */ public function key() { return $this->getBuffer()->current()[self::BUFFER_KEY]; } /** * Move forward to next element. * * @return void */ public function next() { $innerIterator = $this->getInnerIterator(); $buffer = $this->getBuffer(); $buffer->next(); // End of the buffer, need a new value. if (false === $buffer->valid()) { for ( $bufferSize = count($buffer), $maximumBufferSize = $this->getBufferSize(); $bufferSize >= $maximumBufferSize; --$bufferSize ) { $buffer->shift(); } $innerIterator->next(); $buffer->push([ self::BUFFER_KEY => $innerIterator->key(), self::BUFFER_VALUE => $innerIterator->current() ]); // Seek to the end of the buffer. $buffer->setIteratorMode($buffer::IT_MODE_LIFO | $buffer::IT_MODE_KEEP); $buffer->rewind(); $buffer->setIteratorMode($buffer::IT_MODE_FIFO | $buffer::IT_MODE_KEEP); } return; } /** * Move backward to previous element. * * @return void */ public function previous() { $this->getBuffer()->prev(); return; } /** * Rewind the iterator to the first element. * * @return void */ public function rewind() { $innerIterator = $this->getInnerIterator(); $buffer = $this->getBuffer(); $innerIterator->rewind(); if (true === $buffer->isEmpty()) { $buffer->push([ self::BUFFER_KEY => $innerIterator->key(), self::BUFFER_VALUE => $innerIterator->current() ]); } $buffer->rewind(); return; } /** * Check if current position is valid. * * @return bool */ public function valid() { return $this->getBuffer()->valid() && $this->getInnerIterator()->valid(); } }