1 package gnu.xquery.util; 2 import gnu.lists.*; 3 import gnu.mapping.*; 4 import gnu.kawa.functions.NumberCompare; 5 import gnu.kawa.xml.KNode; 6 import gnu.kawa.xml.UntypedAtomic; 7 8 21 22 public class OrderedTuples extends FilterConsumer 23 { 24 25 int n; 26 27 28 Object [] tuples; 30 38 Object [] comps; 39 40 41 int first; 42 47 int[] next; 48 49 50 Procedure body; 51 52 public void writeObject(Object v) 53 { 54 if (n >= tuples.length) 55 { 56 Object [] tmp = new Object [2 * n]; 57 System.arraycopy(tuples, 0, tmp, 0, n); 58 tuples = tmp; 59 } 60 tuples[n++] = v; 61 } 62 63 OrderedTuples () 64 { 65 super(null); 66 tuples = new Object [10]; 67 } 68 69 public static OrderedTuples make$V (Procedure body, Object [] comps) 70 { 71 OrderedTuples tuples = new OrderedTuples(); 72 tuples.comps = comps; 73 tuples.body = body; 74 return tuples; 75 } 76 77 public void run$X (CallContext ctx) throws Throwable 78 { 79 first = listsort(0); 80 emit(ctx); 81 } 82 83 void emit (CallContext ctx) throws Throwable 84 { 85 for (int p = first; p >= 0; p = next[p]) 86 emit(p, ctx); 87 } 88 89 void emit (int index, CallContext ctx) throws Throwable 90 { 91 Object [] args = (Object []) tuples[index]; 92 body.checkN(args, ctx); 93 ctx.runUntilDone(); 94 } 95 96 102 109 110 134 135 int cmp(int a, int b) throws Throwable 136 { 137 for (int i = 0; i < comps.length; i += 3) 138 { 139 Procedure comparator = (Procedure) comps[i]; 140 String flags = (String ) comps[i+1]; 141 NamedCollator collator = (NamedCollator) comps[i+2]; 142 if (collator == null) 143 collator = NamedCollator.codepointCollation; 144 Object val1 = comparator.applyN((Object []) tuples[a]); 145 Object val2 = comparator.applyN((Object []) tuples[b]); 146 val1 = KNode.atomicValue(val1); 147 val2 = KNode.atomicValue(val2); 148 if (val1 instanceof UntypedAtomic) 149 val1 = val1.toString(); 150 if (val2 instanceof UntypedAtomic) 151 val2 = val2.toString(); 152 boolean empty1 = SequenceUtils.isEmptySequence(val1); 153 boolean empty2 = SequenceUtils.isEmptySequence(val2); 154 if (empty1 && empty2) 155 continue; 156 int c; 157 if (empty1 || empty2) 158 { 159 char emptyOrder = flags.charAt(1); 160 c = empty1 == (emptyOrder == 'L') ? -1 : 1; 161 } 162 else 163 { 164 boolean isNaN1 = val1 instanceof Number 165 && Double.isNaN(((Number ) val1).doubleValue()); 166 boolean isNaN2 = val2 instanceof Number 167 && Double.isNaN(((Number ) val2).doubleValue()); 168 if (isNaN1 && isNaN2) 169 continue; 170 if (isNaN1 || isNaN2) 171 { 172 char emptyOrder = flags.charAt(1); 173 c = isNaN1 == (emptyOrder == 'L') ? -1 : 1; 174 } 175 else if (val1 instanceof Number && val2 instanceof Number ) 176 c = NumberCompare.compare(val1, val2, false); 177 else 178 c = collator.compare(val1.toString(), val2.toString()); 179 } 180 if (c == 0) 181 continue; 182 return flags.charAt(0) == 'A' ? c : -c; 183 } 184 return 0; 185 } 186 187 199 int listsort(int list) throws Throwable 200 { int p, q, e, tail, oldhead; 202 int insize, nmerges, psize, qsize, i; 203 204 208 if (n == 0) 209 return -1; 210 211 next = new int[n]; 212 213 for (i = 1; ; i++) 214 { 215 if (i == n) 216 { 217 next[i-1] = -1; 218 break; 219 } 220 else 221 next[i-1] = i; 222 } 223 224 insize = 1; 225 226 for (;;) { 227 p = list; 228 list = -1; 229 tail = -1; 230 231 nmerges = 0; 232 233 while (p >= 0) { 234 nmerges++; 235 236 q = p; 237 psize = 0; 238 for (i = 0; i < insize; i++) { 239 psize++; 240 q = next[q]; 241 if (q < 0) break; 242 } 243 244 qsize = insize; 245 246 247 while (psize > 0 || (qsize > 0 && q >= 0)) { 248 249 250 if (psize == 0) { 251 252 e = q; q = next[q]; qsize--; 253 } else if (qsize == 0 || q < 0) { 254 255 e = p; p = next[p]; psize--; 256 } else if (cmp(p,q) <= 0) { 257 259 e = p; p = next[p]; psize--; 260 } else { 261 262 e = q; q = next[q]; qsize--; 263 } 264 265 266 if (tail >= 0) 267 next[tail] = e; 268 else 269 list = e; 270 tail = e; 271 } 272 273 274 p = q; 275 } 276 next[tail] = -1; 277 278 279 if (nmerges <= 1) 280 return list; 281 282 283 insize *= 2; 284 } 285 } 286 } 287 | Popular Tags |