|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
using System.Xml.XPath;
namespace MS.Internal.Xml.XPath
{
internal sealed class XPathMultyIterator : ResettableIterator
{
private readonly ResettableIterator[] arr;
private int firstNotEmpty;
private int position;
public XPathMultyIterator(ArrayList inputArray)
{
// NOTE: We do not clone the passed inputArray supposing that it is not changed outside of this class
this.arr = new ResettableIterator[inputArray.Count];
for (int i = 0; i < this.arr.Length; i++)
{
var iterator = (ArrayList?)inputArray[i];
Debug.Assert(iterator != null);
this.arr[i] = new XPathArrayIterator(iterator);
}
Init();
}
private void Init()
{
for (int i = 0; i < arr.Length; i++)
{
Advance(i);
}
for (int i = arr.Length - 2; firstNotEmpty <= i;)
{
if (SiftItem(i))
{
i--;
}
}
}
// returns false is iterator at pos reached it's end & as a result head of the array may be moved
private bool Advance(int pos)
{
if (!arr[pos].MoveNext())
{
if (firstNotEmpty != pos)
{
ResettableIterator empty = arr[pos];
Array.Copy(arr, firstNotEmpty, arr, firstNotEmpty + 1, pos - firstNotEmpty);
arr[firstNotEmpty] = empty;
}
firstNotEmpty++;
return false;
}
return true;
}
// Invariant: a[i] < a[i+1] for i > item
// returns flase is head of the list was moved & as a result consistancy of list depends on head consistancy.
private bool SiftItem(int item)
{
Debug.Assert(firstNotEmpty <= item && item < arr.Length);
ResettableIterator it = arr[item];
while (item + 1 < arr.Length)
{
ResettableIterator itNext = arr[item + 1];
Debug.Assert(it.Current != null && itNext.Current != null);
XmlNodeOrder order = Query.CompareNodes(it.Current, itNext.Current);
if (order == XmlNodeOrder.Before)
{
break;
}
if (order == XmlNodeOrder.After)
{
arr[item] = itNext;
//arr[item + 1] = it;
item++;
}
else
{ // Same
arr[item] = it;
if (!Advance(item))
{
return false;
}
it = arr[item];
}
}
arr[item] = it;
return true;
}
public override void Reset()
{
firstNotEmpty = 0;
position = 0;
for (int i = 0; i < arr.Length; i++)
{
arr[i].Reset();
}
Init();
}
public XPathMultyIterator(XPathMultyIterator it)
{
this.arr = (ResettableIterator[])it.arr.Clone();
this.firstNotEmpty = it.firstNotEmpty;
this.position = it.position;
}
public override XPathNodeIterator Clone()
{
return new XPathMultyIterator(this);
}
public override XPathNavigator? Current
{
get
{
Debug.Assert(position != 0, "MoveNext() wasn't called");
Debug.Assert(firstNotEmpty < arr.Length, "MoveNext() returned false");
return arr[firstNotEmpty].Current;
}
}
public override int CurrentPosition { get { return position; } }
public override bool MoveNext()
{
// NOTE: MoveNext() may be called even if the previous call to MoveNext() returned false, SQLBUDT 330810
if (firstNotEmpty >= arr.Length)
{
return false;
}
if (position != 0)
{
if (Advance(firstNotEmpty))
{
SiftItem(firstNotEmpty);
}
if (firstNotEmpty >= arr.Length)
{
return false;
}
}
position++;
return true;
}
}
}
|