1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
//------------------------------------------------------------------------------
// <copyright file="XPathMultyIterator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
namespace MS.Internal.Xml.XPath {
using System;
using System.Xml;
using System.Xml.XPath;
using System.Diagnostics;
using System.Globalization;
using System.Collections;
internal class XPathMultyIterator: ResetableIterator {
protected ResetableIterator[] arr;
protected int firstNotEmpty;
protected 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 ResetableIterator[inputArray.Count];
for (int i = 0; i < this.arr.Length; i ++) {
this.arr[i] = new XPathArrayIterator((ArrayList) inputArray[i]);
}
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
bool Advance(int pos) {
if (! arr[pos].MoveNext()) {
if (firstNotEmpty != pos) {
ResetableIterator empty = arr[pos];
Array.Copy(arr, firstNotEmpty, arr, firstNotEmpty + 1, pos - firstNotEmpty);
arr[firstNotEmpty] = empty;
}
firstNotEmpty ++;
return false;
}
return true;
}
#if false
string dump { get { return Dump(); } }
string Dump(ResetableIterator it) {
it = (ResetableIterator) it.Clone();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("(");
do {
XPathNavigator nav = it.Current.Clone();
nav.MoveToAttribute("id1", "");
sb.Append(nav.Value);
sb.Append(", ");
} while (it.MoveNext());
sb.Length = sb.Length - 2;
sb.Append(")");
return sb.ToString();
}
string Dump() {
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < arr.Length; i ++) {
sb.Append(i);
sb.Append(": ");
if (i < firstNotEmpty) {
sb.Append("()");
} else {
sb.Append(Dump(arr[i]));
}
sb.Append("; ");
}
return sb.ToString();
}
#endif
// 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.
bool SiftItem(int item) {
Debug.Assert(firstNotEmpty <= item && item < arr.Length);
ResetableIterator it = arr[item];
while (item + 1 < arr.Length) {
XmlNodeOrder order = Query.CompareNodes(it.Current, arr[item + 1].Current);
if (order == XmlNodeOrder.Before) {
break;
}
if (order == XmlNodeOrder.After) {
arr[item] = arr[item + 1];
//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 = (ResetableIterator[]) 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;
}
}
}
|