1 4 package gnu.xquery.util; 5 import gnu.mapping.Values; 6 import gnu.mapping.*; 7 import gnu.lists.*; 8 import gnu.xml.NodeTree; 9 import gnu.kawa.xml.*; 10 import gnu.math.DFloNum; 11 12 14 15 public class SequenceUtils 16 { 17 public static Object zeroOrOne (Object arg) 18 { 19 if (arg instanceof Values && ! ((Values) arg).isEmpty()) 21 throw new IllegalArgumentException (); 22 return arg; 23 } 24 25 public static Object oneOrMore (Object arg) 26 { 27 if (arg instanceof Values && ((Values) arg).isEmpty()) 28 throw new IllegalArgumentException (); 29 return arg; 30 } 31 32 public static Object exactlyOne (Object arg) 33 { 34 if (arg instanceof Values) 36 throw new IllegalArgumentException (); 37 return arg; 38 } 39 40 public static boolean isEmptySequence(Object arg) 41 { 42 return arg instanceof Values && ((Values) arg).isEmpty(); 43 } 44 45 public static boolean exists (Object arg) 46 { 47 return ! (arg instanceof Values && ((Values) arg).isEmpty()); 48 } 49 50 public static void insertBefore$X (Object target, long position, 51 Object inserts, CallContext ctx) 52 { 53 Consumer out = ctx.consumer; 54 boolean written = false; 55 if (position <= 0) 56 position = 1; 57 if (target instanceof Values) 58 { 59 Values values = (Values) target; 60 int ipos = 0; 61 long i = 0; 62 for (;;) 63 { 64 int next = values.nextPos(ipos); 65 if ((next == 0 && ! written) || ++i == position) 66 { 67 Values.writeValues(inserts, out); 68 written = true; 69 } 70 if (next == 0) 71 break; 72 values.consumePosRange(ipos, next, out); 73 ipos = next; 74 } 75 } 76 else 77 { 78 if (position <= 1) 79 Values.writeValues(inserts, out); 80 out.writeObject(target); 81 if (position > 1) 82 Values.writeValues(inserts, out); 83 } 84 } 85 86 public static void remove$X (Object arg, long position, CallContext ctx) 87 { 88 Consumer out = ctx.consumer; 89 if (arg instanceof Values) 90 { 91 Values values = (Values) arg; 92 int ipos = 0; 93 long i = 0; 94 for (;;) 95 { 96 int next = values.nextPos(ipos); 97 if (next == 0) 98 break; 99 if (++i != position ) 100 values.consumePosRange(ipos, next, out); 101 ipos = next; 102 } 103 } 104 else if (position != 1) 105 out.writeObject(arg); 106 } 107 108 109 public static void reverse$X (Object arg, CallContext ctx) 110 { 111 Consumer out = ctx.consumer; 112 if (! (arg instanceof Values)) 113 { 114 out.writeObject(arg); 115 return; 116 } 117 Values vals = (Values) arg; 118 int ipos = 0; 119 int[] poses = new int[100]; 120 int n = 0; 121 for (;;) 122 { 123 if (n >= poses.length) 124 { 125 int[] t = new int[2 * n]; 126 System.arraycopy(poses, 0, t, 0, n); 127 poses = t; 128 } 129 poses[n++] = ipos; 130 ipos = vals.nextPos(ipos); 131 if (ipos == 0) 132 break; 133 } 134 for (int i = n-1; --i >= 0; ) 135 vals.consumePosRange(poses[i], poses[i+1], out); 136 } 137 138 public static void indexOf$X (Object seqParam, Object srchParam, 139 NamedCollator collator, CallContext ctx) 140 { 141 Consumer out = ctx.consumer; 142 if (seqParam instanceof Values) 143 { 144 Values vals = (Values) seqParam; 145 int ipos = vals.startPos(); 146 int i = 1; 147 for (; (ipos = vals.nextPos(ipos)) != 0; i++) 148 if (Compare.apply(Compare.LENIENT_EQ, 149 vals.getPosPrevious(ipos), 150 srchParam, collator)) 151 out.writeInt(i); 152 } 153 else if (Compare.apply(Compare.LENIENT_EQ, seqParam, srchParam, collator)) 154 out.writeInt(1); 155 } 156 157 public static final NodeType textOrElement 158 = new NodeType("element-or-text", NodeType.GROUP_OK|NodeType.TEXT_OK); 159 160 public static boolean deepEqualChildren (NodeTree seq1, int ipos1, 161 NodeTree seq2, int ipos2, 162 NamedCollator collator) 163 { 164 NodeType filter = textOrElement; 165 int child1 = seq1.firstChildPos(ipos1, filter); 166 int child2 = seq2.firstChildPos(ipos2, filter); 167 for (;;) 168 { 169 if (child1 == 0 || child2 == 0) 170 return child1 == child2; 171 if (! deepEqual(seq1, child1, seq2, child2, collator)) 172 return false; 173 child1 = seq1.nextMatching(child1, filter, -1, false); 174 child2 = seq2.nextMatching(child2, filter, -1, false); 175 } 176 } 177 178 public static boolean deepEqual (NodeTree seq1, int ipos1, 179 NodeTree seq2, int ipos2, 180 NamedCollator collator) 181 { 182 int kind1 = seq1.getNextKind(ipos1); 183 int kind2 = seq1.getNextKind(ipos2); 184 switch (kind1) 185 { 186 case Sequence.GROUP_VALUE: 187 if (kind1 != kind2) 188 return false; 189 String loc1 = seq1.posLocalName(ipos1); 191 String loc2 = seq2.posLocalName(ipos2); 192 if (loc1 != loc2) 193 return false; 194 String ns1 = seq1.posNamespaceURI(ipos1); 195 String ns2 = seq2.posNamespaceURI(ipos2); 196 if (ns1 != ns2) 197 return false; 198 int attr1 = seq1.firstAttributePos(ipos1); 199 int nattr1 = 0; 200 for (;;) 201 { 202 if (attr1 == 0 203 || seq1.getNextKind(attr1) != Sequence.ATTRIBUTE_VALUE) 204 break; 205 nattr1++; 206 String local = seq1.posLocalName(attr1); 207 String ns = seq1.posNamespaceURI(attr1); 208 int attr2 = seq2.getAttributeI(ipos2, ns, local); 209 if (attr2 == 0) 210 return false; 211 String aval1 = KNode.getNodeValue(seq1, attr1); 212 String aval2 = KNode.getNodeValue(seq2, attr2); 213 if (! deepEqualItems(aval1, aval2, collator)) 214 return false; 215 attr1 = seq1.nextPos(attr1); 216 } 217 int nattr2 = seq2.getAttributeCount(ipos2); 218 if (nattr1 != nattr2) 219 return false; 220 221 case Sequence.DOCUMENT_VALUE: 222 return deepEqualChildren(seq1, ipos1, seq2, ipos2, collator); 223 case Sequence.ATTRIBUTE_VALUE: 224 if (seq1.posLocalName(ipos1) != seq2.posLocalName(ipos2) 225 || seq1.posNamespaceURI(ipos1) != seq2.posNamespaceURI(ipos2)) 226 return false; 227 return deepEqualItems(KAttr.getObjectValue(seq1, ipos1), 228 KAttr.getObjectValue(seq2, ipos2), 229 collator); 230 case Sequence.PROCESSING_INSTRUCTION_VALUE: 231 if (! seq1.posTarget(ipos1).equals(seq2.posTarget(ipos2))) 232 return false; 233 return KNode.getNodeValue(seq1, ipos1) 234 .equals(KNode.getNodeValue(seq2, ipos2)); 235 case Sequence.COMMENT_VALUE: 236 case Sequence.CDATA_VALUE: 237 default: 238 if (kind1 != kind2) 239 return false; 240 return KNode.getNodeValue(seq1, ipos1) 241 .equals(KNode.getNodeValue(seq2, ipos2)); 242 } 243 } 244 245 public static boolean deepEqualItems (Object arg1, Object arg2, 246 NamedCollator collator) 247 { 248 if (NumberValue.isNaN(arg1) && NumberValue.isNaN(arg2)) 249 return true; 250 return Compare.atomicCompare(Compare.TRUE_IF_EQU, arg1, arg2, collator); 251 } 252 253 public static boolean deepEqual (Object arg1, Object arg2, 254 NamedCollator collator) 255 { 256 if (arg1 == arg2) 257 return true; 258 if (arg1 == null || arg1 == Values.empty) 259 return arg2 == null || arg2 == Values.empty; 260 if (arg2 == null || arg2 == Values.empty) 261 return false; 262 int ipos1 = 1, ipos2 = 1; 263 boolean is1seq = arg1 instanceof Values; 264 boolean is2seq = arg2 instanceof Values; 265 Values vals1 = is1seq ? (Values) arg1 : null; 266 Values vals2 = is2seq ? (Values) arg2 : null; 267 boolean first = true; 268 for (;;) 269 { 270 if (is1seq) 271 { 272 if (first) 273 ipos1 = vals1.startPos(); 274 ipos1 = vals1.nextPos(ipos1); 275 } 276 if (is2seq) 277 { 278 if (first) 279 ipos2 = vals2.startPos(); 280 ipos2 = vals2.nextPos(ipos2); 281 } 282 if (ipos1 == 0 || ipos2 == 0) 283 return ipos1 == ipos2; 284 Object item1 = is1seq ? vals1.getPosPrevious(ipos1) : arg1; 285 Object item2 = is2seq ? vals2.getPosPrevious(ipos2) : arg2; 286 287 if (! (item1 instanceof KNode) && !( item2 instanceof KNode)) 288 { 289 try 290 { 291 if (! deepEqualItems(arg1, arg2, collator)) 292 return false; 293 } 294 catch (Throwable ex) 295 { 296 return false; 297 } 298 } 299 else if (item1 instanceof KNode && item2 instanceof KNode) 300 { 301 KNode node1 = (KNode) item1; 302 KNode node2 = (KNode) item2; 303 if (! deepEqual((NodeTree) node1.sequence, node1.ipos, 304 (NodeTree) node2.sequence, node2.ipos, 305 collator)) 306 return false; 307 } 308 else 309 return false; 310 311 if (first) 312 { 313 first = false; 314 if (! is1seq) 315 ipos1 = 0; 316 if (! is2seq) 317 ipos2 = 0; 318 } 319 } 320 } 321 } 322 | Popular Tags |