DistinctIterator
@param XPath2NodeIterator $iter
@param string $collation
@return IEnumerable
353224
private static function DistinctIterator( $iter, $collation = null )
	{
		$dict = array();
		$comparer = new DistinctComparer( $collation );

		$iter = $iter->CloneInstance();
		$iter->Reset();
		while ( $iter->MoveNext() )
		{
			/**
			 * @var XPathItem $item
			 */
		    $item = $iter->getCurrent();
		    if ( strlen( (string)$item->getValue() ) )
		    {
				$value = $item instanceof DOMXPathNavigator // || $item instanceof XPath2Item
					? $item->GetTypedValue()
					: $item;

				$found = false;
				foreach ( $dict as $itemComparer )
				{
					if ( $comparer->Compare( $itemComparer, $value ) == 0 )
					{
						$found = true;
						break;
					}
				}
				if ( ! $found )
				{
					yield $item instanceof XPath2Item
						? $item
						: XPath2Item::fromValue( $value );
					$dict[] = $value;
				}
			}
		}
	}
176452
protected function fromElementOrderNodeIteratorParts( $baseIter )
	{
		$isNode = null;
		$this->itemSet = array();
		while ( $baseIter->MoveNext() )
		{
			// BMS 2018-01-08 Changed to be more careful about when getIsNode() is called
			//                Same change must be made to DocumentOrderNodeIterator
			$current = $baseIter->getCurrent();

			if ( is_null( $isNode ) )
			{
				$isNode = $current instanceof XPathNavigator && $current->getIsNode();
			}
			else
			{
				if ( ( ! $isNode && $current instanceof XPathNavigator ) || ( $isNode && $current->getIsNode() != $isNode ) )
				{
					throw XPath2Exception::withErrorCodeAndParam( "XPTY0018", Resources::XPTY0018, $baseIter->getCurrent()->getValue() );
				}
			}

			/**
			 * @var DOMXPathItem $clone
			 */
			$clone = CoreFuncs::CloneInstance( $baseIter->getCurrent() );
			$localName = $clone->getLocalName();

			$this->itemSet[ $localName ][] = $clone;
		}

		if ( ! is_null( $isNode ) && $isNode )
		{
			if ( count( $this->itemSet ) > 1 )
			{
				ksort( $this->itemSet );
			}

			foreach ( $this->itemSet as $elementName => $element )
			{
				if ( count( $element ) < 2 ) continue;

				$comparer = new XPathComparer();
				$result = usort( $this->itemSet[ $elementName ], function( $a, $b )
				{
					return strcasecmp( $a->getValue(), $b->getValue() );
				} );
			}

		}
	}
439027
public function getIterator(): \Iterator
    {
        $hydrator = $this->documentManager->newHydrator($this->hydrationMode);
        $query = clone $this->query;

        if (! $query->hasParam('_source')) {
            /** @var DocumentMetadata $class */
            $class = $this->documentManager->getClassMetadata($this->documentClass);
            $query->setSource($class->eagerFieldNames);
        }

        if (null !== $this->sort) {
            $query->setSort($this->sort);
        }

        if (null !== $this->limit) {
            $query->setSize($this->limit);
        }

        if (null !== $this->offset) {
            $query->setFrom($this->offset);
        }

        $generator = null !== $this->cacheProfile ? $this->_doExecuteCached($query) : $this->_doExecute($query);
        foreach ($generator as $resultSet) {
            yield from $hydrator->hydrateAll($resultSet, $this->documentClass);
        }
    }
501750
public function collection(TableQueryIterator $iterator, Table $definition) : Collection
    {
        return Collection::from($iterator)
            ->map(function ($v) use ($definition) {
                return $this->entity($definition, $v);
            });
    }
470864
protected function _setIterator($iterator)
    {
        if ($iterator !== null && !($iterator instanceof Iterator)) {
            throw $this->_createInvalidArgumentException(
                $this->__('Invalid iterator'),
                null,
                null,
                $iterator
            );
        }

        $this->iterator = $iterator;
    }
408228
private function parseIterator(Iterator $iterator)
    {
        $iterator = $this->parseHeaderRow($iterator);
        if ($this->csvFormat->getDataStart() > 1 || $this->csvFormat->getLimit() !== -1) {
            $iterator = new LimitIterator(
                $iterator,
                max(0, $this->csvFormat->getDataStart() - 1),
                $this->csvFormat->getLimit()
            );
        }
        return $iterator;
    }
1226622
protected function fromAxisNodeIteratorParts( $context, $nodeTest, $matchSelf, $iter )
	{
		$this->context = $context;
		if ( $nodeTest instanceof QName )
		{
			$this->nameTest = $nodeTest;
		}
		else if ( $nodeTest instanceof SequenceType && $nodeTest != SequenceTypes::$Node )
		{
			$this->typeTest = $nodeTest;
		}

		$this->matchSelf = $matchSelf;
		$this->iter = $iter;
	}
459868
public function DeepEqualByIteratorx( $iter1, $iter2 )
	{
		$iter1 = $iter1->CloneInstance();
		$iter2 = $iter2->CloneInstance();
		$flag1 = false;
		$flag2 = false;

		do
		{
			$flag1 = $iter1->MoveNext();
			$flag2 = $iter2->MoveNext();
			if ( $flag1 != $flag2 ) return false;

			if (! $flag1 && ! $flag2) return true;

			$iter1Current = $iter1->getCurrent();
			$iter2Current = $iter2->getCurrent();

			// If one of the iterators is a ForIterator and it returns an ExprIterator handle it
			if ( $iter1Current instanceof ExprIterator || $iter2Current instanceof ExprIterator )
			{
				if ( ! $iter1Current instanceof ExprIterator ) $iter1Current = $iter1;
				if ( ! $iter2Current instanceof ExprIterator ) $iter2Current = $iter2;
				return $this->DeepEqualByIterator( $iter1Current->CloneInstance(), $iter2Current->CloneInstance() );
			}

			if ( $iter1Current->getIsNode() != $iter2Current->getIsNode() )
			{
				return false;
			}
			else
			{
				if ( $iter1Current->getIsNode() && $iter2Current->getIsNode() )
				{
					if ( ! $this->NodeEqual( $iter1Current, $iter2Current ) )
					{
						return false;
					}
				}
				else
				{
					if ( ! $this->ItemEqual( $iter1Current, $iter2Current ) )
					{
						return false;
					}
				}
			}
		}
		while ( true );
		return true;
	}
1359009
public function unique(array $elements, Closure $iterator = null)
    {
        if ( ! is_null($iterator))
        {
            $elements = array_filter($elements, $iterator);
        }
        else
        {
            $elements = array_unique($elements);
        }

        return array_values($elements);
    }
284969
public static function WriteTraceWithLabel( $context, $iter, $label )
	{
		$sb = array();

		/**
		 * @var XPathItem $item
		 */
		foreach ( $iter as $item )
		{
			if ( $item instanceof XPath2NodeIterator )
			{
				$sb[] = ExtFuncs::StringJoin( $item, " " );
			}
		    else if ( $item->getIsNode() )
		    {
				/**
				 * @var XPathNavigator $nav
				 */
		    	$nav = $item;
				$sb[] = $nav->OuterXml;
		    }
		    else
		    {
		    	$sb[] = $item->getValue();
		    }

		}

		error_log( ( empty( $label ) ? "" : "$label " ) . implode( ", ", $sb ) );

		// if ( $item instanceof ExprIterator )
		// {
		// 	return $item;
		// }

		$iter->Reset();
		return $iter;

		$mapped = array_map( function( $item ) { return new ValueNode( null, $item ); }, $sb );
		return ExprIterator::fromNodes( $mapped, null, null );
	}
959629
public CollationElementIterator getCollationElementIterator(CharacterIterator source) {
        initMaxExpansions();
        CharacterIterator newsource = (CharacterIterator) source.clone();
        return new CollationElementIterator(newsource, this);
    }
725167
protected function getArrayFromXml(SimpleXmlIterator $iterator)
    {
        $result = [];

        for($iterator->rewind(); $iterator->valid(); $iterator->next())
        {
            if($iterator->hasChildren())
            {
                foreach($iterator->getChildren() as $key => $value)
                {
                    if(1 <= $value->count())
                    {
                        $result[$iterator->key()][][$key] = $this->getArrayFromXml($value);
                    }
                    else
                    {
                        if(true === $value->hasChildren())
                        {
                            $result[$iterator->key()][$key] = $this->getArrayFromXml($value);
                        }
                        else
                        {
                            $result[$iterator->key()] = $this->getArrayFromXml($iterator->current());
                        }
                    }
                }
            }
            else
            {
                $result[$iterator->key()] = $this->convertToStringOrBoolean($iterator->current());
            }
        }

        return $result;
    }
619711
private static Iterator<String> getBaseIterator(BufferedReader reader,
                                                    boolean keepOrdering) {

        // The final iterator is how the stream will be tokenized after all the
        // tokenizing options have been applied.  This value is iteratively set
        // as the options are applied
        Iterator<String> finalIterator = new WordIterator(reader);

        // STEP 1: APPLY TOKEN REPLACEMENT
        if (replacementMap != null)
            finalIterator = 
                new WordReplacementIterator(finalIterator, replacementMap);

        // STEP 2: APPLY COMPOUND TOKENIZING
        if (compoundTokens != null) {
            // Because the initialization step for a CWI has some overhead, use
            // the reset to keep the same tokens.  However, multiple threads may
            // be each using their own CWI, so keep Thread-local storage of what
            // CWI is being used to avoid resetting another thread's iterator.
            CompoundWordIterator cwi = 
                compoundIterators.get(Thread.currentThread());
            if (cwi == null) {
                cwi = new CompoundWordIterator(finalIterator, compoundTokens);
                compoundIterators.put(Thread.currentThread(), cwi);
            } else {
                // NOTE: if the underlying set of valid compound words is ever
                // changed, the iterator returned from the compoundIterators map
                // will have been updated by the setProperties() call, so this
                // method is guaranteed to pick up the latest set of compound
                // words
                cwi.reset(finalIterator);
            }
            finalIterator = cwi;
        } 

        // STEP 3: APPLY TOKEN LIMITING
        if (wordLimit > 0)
            finalIterator = new LimitedIterator<String>(
                    finalIterator, wordLimit);

        // STEP 4: APPLY TOKEN FILTERING
        if (filter != null) {
            finalIterator = (keepOrdering)
                ? new OrderPreservingFilteredIterator(finalIterator, filter)
                : new FilteredIterator(finalIterator, filter);
        }

        // STEP 5: APPLY STEMMING
        if (stemmer != null) 
            finalIterator = new StemmingIterator(finalIterator, stemmer);

        return finalIterator;
    }
948590
public function CreateWithIterator( $context, $dataPool, $baseIter, $special )
	{
		switch ( $this->type )
		{
			case XPath2ExprType::Attribute:
				return AttributeNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Child:

				if ( $special && $this->nodeTest != SequenceTypes::$Node )
					return new SpecialChildNodeIterator( $context, $this->nodeTest, $baseIter );

				return ChildNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Descendant:

				if ( $special && $this->nodeTest != SequenceTypes::$Node )
					return new SpecialDescendantNodeIterator( $context, $this->nodeTest, false, $baseIter );

				return DescendantNodeIterator::fromNodeTest( $context, $this->nodeTest, false, $baseIter );

			case XPath2ExprType::DescendantOrSelf:

				if ( $special && $this->nodeTest != SequenceTypes::$Node )
					return SpecialDescendantNodeIterator::fromNodeTest( $context, $this->nodeTest, true, $baseIter );

				return DescendantNodeIterator::fromNodeTest( $context, $this->nodeTest, true, $baseIter );

			case XPath2ExprType::Ancestor:

				return AncestorNodeIterator::fromParts( $context, $this->nodeTest, false, $baseIter );

			case XPath2ExprType::AncestorOrSelf:

				return AncestorNodeIterator::fromParts( $context, $this->nodeTest, true, $baseIter );

			case XPath2ExprType::Following:

				return FollowingNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::FollowingSibling:

				return FollowingSiblingNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Parent:

				return ParentNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Preceding:

				return PrecedingNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::PrecedingSibling:

				return PrecedingSiblingNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::NamespaceUri:

				return NamespaceNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Self:

				return SelfNodeIterator::fromNodeTest( $context, $this->nodeTest, $baseIter );

			case XPath2ExprType::Expr:

				return ExprNodeIterator::fromParts( $context, $this->node, $dataPool, $baseIter );

			case XPath2ExprType::PositionFilter:

				return new PositionFilterNodeIterator( Convert::ToInt32( $this->nodeTest ), $baseIter );

			case XPath2ExprType::ChildOverDescendants:

				return ChildOverDescendantsNodeIterator::fromParts( $context, /* ChildOverDescendantsNodeIterator.NodeTest[] */ $this->nodeTest, $baseIter );

			default:

				return null;
		}
	}
652785
protected function buildOrderBy(Iterator $iterator): Iterator
    {
        if ([] === $this->order_by) {
            return $iterator;
        }

        $compare = function (array $record_a, array $record_b): int {
            foreach ($this->order_by as $callable) {
                if (0 !== ($cmp = $callable($record_a, $record_b))) {
                    return $cmp;
                }
            }

            return $cmp ?? 0;
        };

        $iterator = new ArrayIterator(iterator_to_array($iterator));
        $iterator->uasort($compare);

        return $iterator;
    }
674722
public static function StringJoin( $iter, $s )
	{
		if ( $s instanceof Undefined )
		{
			return Undefined::getValue();
		}

		$str = $s . "";
		$sb = array();
		$types = SchemaTypes::getInstance();

		/**
		 * @var XPathItem $item
		 */
		foreach ( $iter as $item )
		{
	    	if ( $item instanceof XPathNavigator )
			{
				/**
				 * @var XPathNavigator $nav
				 */
				$nav = $item;
				if ( ! is_null( $nav->getSchemaInfo() ) )
				{
					if ( ! is_null( $nav->getSchemaInfo()->getSchemaType() ) )
					{
						if ( ! ( $nav->getSchemaInfo()->getSchemaType() instanceof XmlSchemaSimpleType ) )
						{
							throw XPath2Exception::withErrorCodeAndParam( "FOTY0012", Resources::FOTY0012 . ". The node cannot be used as an argument to the string-join function.", new XmlQualifiedNameTest( $nav->LocalName, $nav->NamespaceURI, false ) );
						}
					}

					$qname = $nav->getSchemaInfo()->getSchemaType()->QualifiedName;
					$type = "{$qname->prefix}:{$qname->localName}";

					if ( ! $types->resolvesToBaseType( $type, array( 'xs:string', 'xsd:string' ) ) )
					{
						throw XPath2Exception::withErrorCodeAndParams( "XPTY0004", Resources::XPTY0004, array( $type, 'xs:string' ) );
					}
				}
			}

	    	$sb[] = $item->getValue();
		}

		return implode( $str, $sb );
	}
1085483
private function CreateEnumerator( $dataPool, $expr, $baseIter )
	{
		/**
		 * @var XPath2NodeIterator $iter
		 */
		$iter = $baseIter->CloneInstance();

		if ( $expr instanceof ValueNode )
		{
			/**
			 * @var ValueNode $numexpr
			 */
			$numexpr = $expr;

			if ( is_numeric( $numexpr->getContent() ) || $numexpr->getContent() instanceof Integer )
			{
				/**
				 * @var Integer $pos
				 */
				// $pos = Integer::fromValue( $numexpr->getContent() );
				$pos = $numexpr->getContent(); // Convert::ToInt( $numexpr->getContent(), null );
				/**
				 * @var XPathItem $item
				 */
				foreach ( $iter as $item )
				{
					if ( $pos == 1)
					{
						yield $item;
						break;
					}
					else
						$pos--;
				}


				return;
			}
		}

		/**
		 * @var ContextProvider $provider
		 */
		$provider = ContextProvider::fromIterator( $iter );
		$res = Undefined::getValue();
		while ( $iter->MoveNext() )
		{
			if ( $this->m_contextSensitive || $res instanceof Undefined )
			{
				$res = $expr->Execute( $provider, $dataPool );
			}

			if ( $res instanceof Undefined )
			{
				if ( ! $this->m_contextSensitive )
				{
					break;
				}
				continue;
			}

			/**
			 * @var XPathItem $item
			 */
			$item = null;

			if ( $res instanceof XPath2NodeIterator )
			{
				/**
				 * @var XPath2NodeIterator $iter2
				 */
				$iter2 = $res->CloneInstance();

				if ( ! $iter2->MoveNext() )
				{
					continue;
				}

				/**
				 * @var XPathItem $item
				 */
				$item = CoreFuncs::CloneInstance( $iter2->getCurrent() );

				if ( ! $item->getIsNode() && $iter2->MoveNext() )
				{
				    throw XPath2Exception::withErrorCodeAndParams( "FORG0006", Resources::FORG0006,
						array(
							"fn:boolean()",
							SequenceType::WithTypeCodeAndCardinality( XmlTypeCode::AnyAtomicType, XmlTypeCardinality::OneOrMore )
						)
					);
				}
			}
			else
			{
				$item = $res instanceof XPathItem
					? $item = $res
				    : $item = XPath2Item::fromValue( $res );
			}

			if ( $item->getIsNode() )
			{
				yield $iter->getCurrent();
			}
			else
			{
				if ( ValueProxy::IsNumericValue( $item->getValueType() ) )
				{
				    if ( CoreFuncs::OperatorEq( $iter->getCurrentPosition() + 1, $item->GetTypedValue() ) instanceof TrueValue)
				    {
				        yield $iter->getCurrent();
				        if ( ! $this->m_contextSensitive )
				        {
				        	break;
				        }
				    }
				}
				elseif ( CoreFuncs::GetBooleanValue( $item ) )
				{
					yield $iter->getCurrent();
				}
			}
		}
	}