1 28 29 package com.caucho.es; 30 31 34 class NativeArray extends Native { 35 static ESId LENGTH = ESId.intern("length"); 36 static final int NEW = 1; 37 static final int JOIN = NEW + 1; 38 static final int TO_STRING = JOIN + 1; 39 static final int REVERSE = TO_STRING + 1; 40 static final int SORT = REVERSE + 1; 41 42 static final int CONCAT = SORT + 1; 44 static final int POP = CONCAT + 1; 45 static final int PUSH = POP + 1; 46 static final int SHIFT = PUSH + 1; 47 static final int UNSHIFT = SHIFT + 1; 48 static final int SLICE = UNSHIFT + 1; 49 static final int SPLICE = SLICE + 1; 50 51 54 private NativeArray(String name, int n, int len) 55 { 56 super(name, len); 57 58 this.n = n; 59 } 60 61 64 static ESObject create(Global resin) 65 { 66 Native nativeArray = new NativeArray("Array", NEW, 1); 67 ESArray proto = new ESArray(); 68 proto.prototype = resin.objProto; 69 NativeWrapper array = new NativeWrapper(resin, nativeArray, 70 proto, ESThunk.ARRAY_THUNK); 71 resin.arrayProto = proto; 72 73 put(proto, "join", JOIN, 1); 74 put(proto, "toString", TO_STRING, 0); 75 put(proto, "reverse", REVERSE, 0); 76 put(proto, "sort", SORT, 0); 77 78 put(proto, "concat", CONCAT, 0); 80 put(proto, "pop", POP, 0); 81 put(proto, "push", PUSH, 0); 82 put(proto, "shift", SHIFT, 0); 83 put(proto, "unshift", UNSHIFT, 0); 84 put(proto, "slice", SLICE, 2); 85 put(proto, "splice", SPLICE, 0); 86 87 proto.setClean(); 88 array.setClean(); 89 90 return array; 91 } 92 93 private static void put(ESObject obj, String name, int n, int len) 94 { 95 ESId id = ESId.intern(name); 96 97 obj.put(id, new NativeArray(name, n, len), DONT_ENUM); 98 } 99 100 101 public ESBase call(Call eval, int length) throws Throwable 102 { 103 switch (n) { 104 case NEW: 105 return create(eval, length); 106 107 case JOIN: 108 if (length == 0) 109 return toString(eval, length); 110 else 111 return join(eval, length); 112 113 case TO_STRING: 114 return toString(eval, length); 115 116 case REVERSE: 117 return reverse(eval, length); 118 119 case SORT: 120 return sort(eval, length); 121 122 case CONCAT: 123 return concat(eval, length); 124 125 case POP: 126 return pop(eval, length); 127 128 case PUSH: 129 return push(eval, length); 130 131 case SHIFT: 132 return shift(eval, length); 133 134 case UNSHIFT: 135 return unshift(eval, length); 136 137 case SLICE: 138 return slice(eval, length); 139 140 case SPLICE: 141 return splice(eval, length); 142 143 default: 144 throw new ESException("Unknown object function"); 145 } 146 } 147 148 ESBase create(Call eval, int length) throws Throwable 149 { 150 ESObject obj = Global.getGlobalProto().createArray(); 151 152 if (length == 0) 153 return obj; 154 if (length == 1) { 155 ESBase arg = eval.getArg(0); 156 157 if (arg instanceof ESNumber) 158 obj.setProperty(LENGTH, ESNumber.create(arg.toInt32())); 159 else 160 obj.setProperty(0, arg); 161 162 return obj; 163 } 164 165 for (int i = 0; i < length; i++) 166 obj.setProperty(i, eval.getArg(i)); 167 168 return obj; 169 } 170 171 static ESBase join(ESObject array, String separator) throws Throwable 172 { 173 if (array.mark != 0) { 174 return ESString.create("..."); 175 } 176 array.mark = -1; 177 178 try { 179 int len = array.getProperty(LENGTH).toInt32(); 180 StringBuffer sbuf = new StringBuffer (); 181 182 for (int i = 0; i < len; i++) { 183 if (i != 0) 184 sbuf.append(separator); 185 186 ESBase value = array.hasProperty(i); 187 188 if (value != null && value != esNull && value != esUndefined) 189 sbuf.append(value.toString()); 190 } 191 192 return ESString.create(sbuf.toString()); 193 } finally { 194 array.mark = 0; 195 } 196 } 197 198 ESBase join(Call eval, int length) throws Throwable 199 { 200 String separator = length == 0 ? "," : eval.getArg(0).toString(); 201 202 ESObject array = eval.getArg(-1).toObject(); 203 204 return join(array, separator); 205 } 206 207 static ESBase toString(ESObject array) throws Throwable 208 { 209 return join(array, ","); 210 } 211 212 ESBase toString(Call eval, int length) throws Throwable 214 { 215 ESObject array = eval.getArg(-1).toObject(); 216 217 return toString(array); 218 } 219 220 ESBase reverse(Call eval, int length) throws Throwable 221 { 222 ESObject array = eval.getArg(-1).toObject(); 223 224 int len = (int) array.getProperty(LENGTH).toInt32(); 225 for (int k = 0; k < len / 2; k++) { 226 int firstIndex = k; 227 int secondIndex = len - k - 1; 228 229 ESBase first = array.hasProperty(firstIndex); 230 ESBase second = array.hasProperty(secondIndex); 231 232 if (first == null) 233 array.delete(secondIndex); 234 else 235 array.setProperty(secondIndex, first); 236 237 if (second == null) 238 array.delete(firstIndex); 239 else 240 array.setProperty(firstIndex, second); 241 } 242 243 return array; 244 } 245 246 ESBase sort(Call eval, int length) throws Throwable 247 { 248 ESObject array = eval.getArg(-1).toObject(); 249 250 ESBase cmp = length == 0 ? null : eval.getArg(0); 251 252 int len = (int) array.getProperty(LENGTH).toInt32(); 253 ESBase []values = new ESBase[len]; 254 255 for (int i = 0; i < len; i++) 256 values[i] = array.getProperty("" + i); 257 258 qsort(values, 0, len, cmp); 259 260 for (int i = 0; i < len; i++) { 261 if (values[i] == esUndefined) 262 array.delete("" + i); 263 else 264 array.setProperty("" + i, values[i]); 265 } 266 267 return array; 268 } 269 270 private void qsort(ESBase []array, int offset, int length, ESBase cmp) 271 throws Throwable 272 { 273 if (length == 2) { 274 if (compare(cmp, array[offset], array[offset + 1]) > 0) { 275 ESBase temp = array[offset]; 276 array[offset] = array[offset + 1]; 277 array[offset + 1] = temp; 278 } 279 } else if (length > 2) { 280 int keyIndex = offset + length / 2; 281 ESBase key = array[keyIndex]; 282 int keys = 0; 283 int tail = 0; 284 int val; 285 286 if ((val = compare(cmp, array[offset], key)) > 0) { 287 key = array[offset]; 288 array[offset] = array[keyIndex]; 289 array[keyIndex] = key; 290 } else if (val == 0) 291 keys++; 292 293 if ((val = compare(cmp, key, array[offset + length - 1])) > 0) { 294 key = array[offset + length - 1]; 295 array[offset + length - 1] = array[keyIndex]; 296 array[keyIndex] = key; 297 keys = 0; 298 tail = 1; 299 300 if ((val = compare(cmp, array[offset], key)) > 0) { 301 key = array[offset]; 302 array[offset] = array[keyIndex]; 303 array[keyIndex] = key; 304 } else if (val == 0) 305 keys++; 306 } else if (val < 0) 307 tail = 1; 308 309 int i; 310 if (keyIndex == offset + 1) { 311 i = 2 + tail; 312 keys++; 313 } 314 else 315 i = 1 + tail; 316 317 for (; i < length; i++) { 318 int index = offset + i - tail; 319 320 if (array[index] == key) { 321 keys++; 322 continue; 323 } 324 325 int cmpResult = compare(cmp, key, array[index]); 326 if (cmpResult > 0 && keys != 0) { 327 ESBase temp = array[index]; 328 array[index] = array[index - keys]; 329 array[index - keys] = temp; 330 } else if (cmpResult < 0) { 331 ESBase temp = array[offset + length - tail - 1]; 332 array[offset + length - tail - 1] = array[index]; 333 array[index] = temp; 334 tail += 1; 335 } else if (cmpResult == 0) 336 keys++; 337 } 338 339 if (length - tail - keys > 1) 340 qsort(array, offset, length - tail - keys, cmp); 341 if (tail > 1) 342 qsort(array, offset + length - tail, tail, cmp); 343 } 344 } 345 346 private int compare(ESBase cmp, ESBase a, ESBase b) 347 throws Throwable 348 { 349 if (a == b) 350 return 0; 351 else if (a == esUndefined) 352 return 1; 353 else if (b == esUndefined) 354 return -1; 355 else if (a == esNull) 356 return 1; 357 else if (b == esNull) 358 return -1; 359 else if (cmp != null) { 360 Global resin = Global.getGlobalProto(); 362 Call eval = resin.getCall(); 363 364 eval.stack[0] = esNull; 365 eval.stack[1] = a; 366 eval.stack[2] = b; 367 eval.top = 1; 368 369 int result = cmp.call(eval, 2).toInt32(); 370 371 resin.freeCall(eval); 372 373 return result; 374 } 375 else { 376 String sa = a.toString(); 377 String sb = b.toString(); 378 379 return sa.compareTo(sb); 380 } 381 } 382 383 ESBase concat(Call eval, int length) throws Throwable 384 { 385 ESArray array = Global.getGlobalProto().createArray(); 386 387 int k = 0; 388 for (int i = -1; i < length; i++) { 389 ESBase arg = eval.getArg(i); 390 391 if (arg == esNull || arg == esUndefined || arg == esEmpty) 392 continue; 393 394 ESBase arglen = arg.hasProperty(LENGTH); 395 396 if (arglen == null) { 397 array.setProperty(k++, arg); 398 continue; 399 } 400 401 int len = (int) arglen.toInt32(); 402 403 if (len < 0) { 404 array.setProperty(k++, arg); 405 continue; 406 } 407 408 for (int j = 0; j < len; j++) { 409 ESBase obj = arg.hasProperty(j); 410 411 if (obj != null) 412 array.setProperty(k, obj); 413 k++; 414 } 415 } 416 array.setProperty(LENGTH, ESNumber.create(k)); 417 418 return array; 419 } 420 421 ESBase pop(Call eval, int length) throws Throwable 422 { 423 ESObject obj = eval.getArg(-1).toObject(); 424 425 ESBase lenObj = obj.hasProperty(LENGTH); 426 int len; 427 if (lenObj == null || (len = lenObj.toInt32()) <= 0) 428 return esUndefined; 429 430 ESBase value = obj.getProperty(len - 1); 431 432 obj.setProperty(LENGTH, ESNumber.create(len - 1)); 433 434 return value; 435 } 436 437 ESBase push(Call eval, int length) throws Throwable 438 { 439 ESObject obj = eval.getArg(-1).toObject(); 440 441 ESBase lenObj = obj.getProperty(LENGTH); 442 int len = lenObj.toInt32(); 443 if (len < 0) 444 len = 0; 445 446 for (int i = 0; i < length; i++) 447 obj.setProperty(len + i, eval.getArg(i)); 448 449 ESNumber newLen = ESNumber.create(len + length); 450 obj.setProperty(LENGTH, newLen); 451 452 return newLen; 453 } 454 455 ESBase shift(Call eval, int length) throws Throwable 456 { 457 ESObject obj = eval.getArg(-1).toObject(); 458 459 ESBase lenObj = obj.hasProperty(LENGTH); 460 int len; 461 if (lenObj == null || (len = (int) lenObj.toInt32()) <= 0) 462 return esUndefined; 463 464 ESBase value = obj.getProperty(0); 465 466 for (int i = 1; i < len; i++) { 467 ESBase temp = obj.hasProperty(i); 468 if (temp == null) 469 obj.delete(ESString.create(i - 1)); 470 else 471 obj.setProperty(i - 1, temp); 472 } 473 474 obj.setProperty(LENGTH, ESNumber.create(len - 1)); 475 476 return value; 477 } 478 479 ESBase unshift(Call eval, int length) throws Throwable 480 { 481 ESObject obj = eval.getArg(-1).toObject(); 482 483 ESBase lenObj = obj.getProperty(LENGTH); 484 int len = lenObj.toInt32(); 485 if (len < 0) 486 len = 0; 487 488 if (length == 0) 489 return ESNumber.create(0); 490 491 for (int i = len - 1; i >= 0; i--) { 492 ESBase value = obj.getProperty(i); 493 494 if (value == null) 495 obj.delete(ESString.create(length + i)); 496 else 497 obj.setProperty(length + i, value); 498 } 499 500 for (int i = 0; i < length; i++) { 501 ESBase value = eval.getArg(i); 502 503 if (value == null) 504 obj.delete(ESString.create(i)); 505 else 506 obj.setProperty(i, value); 507 } 508 509 ESNumber numLen = ESNumber.create(len + length); 510 obj.setProperty(LENGTH, numLen); 511 512 return numLen; 513 } 514 515 ESBase slice(Call eval, int length) throws Throwable 516 { 517 ESObject obj = eval.getArg(-1).toObject(); 518 519 ESBase lenObj = obj.getProperty(LENGTH); 520 int len = lenObj.toInt32(); 521 522 ESArray array = Global.getGlobalProto().createArray(); 523 if (len <= 0) 524 return array; 525 526 int start = 0; 527 if (length > 0) 528 start = eval.getArg(0).toInt32(); 529 if (start < 0) 530 start += len; 531 if (start < 0) 532 start = 0; 533 if (start > len) 534 return array; 535 536 int end = len; 537 if (length > 1) 538 end = eval.getArg(1).toInt32(); 539 if (end < 0) 540 end += len; 541 if (end < 0) 542 return array; 543 if (end > len) 544 end = len; 545 546 if (start >= end) 547 return array; 548 549 for (int i = 0; i < end - start; i++) { 550 ESBase value = obj.hasProperty(start + i); 551 552 if (value != null) 553 array.setProperty(i, value); 554 } 555 556 array.setProperty(LENGTH, ESNumber.create(end - start)); 557 558 return array; 559 } 560 561 ESBase splice(Call eval, int length) throws Throwable 562 { 563 if (length < 2) 564 return esUndefined; 565 566 ESObject obj = eval.getArg(-1).toObject(); 567 568 int index = eval.getArg(0).toInt32(); 569 int count = eval.getArg(1).toInt32(); 570 boolean single = count == 1; 571 572 ESBase lenObj = obj.getProperty(LENGTH); 573 int len = lenObj.toInt32(); 574 575 if (index < 0) 576 index += len; 577 if (index < 0) 578 index = 0; 579 580 if (count < 0) 581 count = 0; 582 if (index + count > len) 583 count = len - index; 584 585 ESBase value; 586 587 if (count < 1) 588 value = esUndefined; 589 else { 590 value = Global.getGlobalProto().createArray(); 591 592 for (int i = 0; i < count; i++) 593 value.setProperty(i, obj.getProperty(index + i)); 594 } 595 596 int delta = length - 2 - count; 597 if (delta < 0) { 598 for (int i = 0; i < len - count; i++) { 599 ESBase temp = obj.getProperty(i + index + count); 600 if (temp == null) 601 obj.delete(ESString.create(i + index + count + delta)); 602 else 603 obj.setProperty(i + index + count + delta, temp); 604 } 605 } else if (delta > 0) { 606 for (int i = len - count - 1; i >= 0; i--) { 607 ESBase temp = obj.getProperty(i + index + count); 608 if (temp == null) 609 obj.delete(ESString.create(i + index + count + delta)); 610 else 611 obj.setProperty(i + index + count + delta, temp); 612 } 613 } 614 615 for (int i = 0; i < length - 2; i++) 616 obj.setProperty(i + index, eval.getArg(i + 2)); 617 618 obj.setProperty(LENGTH, ESNumber.create(len - count + length - 2)); 619 620 return value; 621 } 622 623 } 624 | Popular Tags |