Changeset 37089 in webkit for trunk/JavaScriptCore/kjs/ustring.cpp
- Timestamp:
- Sep 29, 2008, 6:31:09 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/ustring.cpp
r36263 r37089 410 410 411 411 // put these early so they can be inlined 412 inline size_t UString::expandedSize(size_t size, size_t otherSize)412 static inline size_t expandedSize(size_t size, size_t otherSize) 413 413 { 414 414 // Do the size calculation in two parts, returning overflowIndicator if … … 435 435 } 436 436 437 void UString::expandCapacity(int requiredLength) 438 { 439 m_rep->checkConsistency(); 440 441 Rep* r = m_rep->baseString; 437 438 static inline bool expandCapacity(UString::Rep* rep, int requiredLength) 439 { 440 rep->checkConsistency(); 441 442 UString::Rep* r = rep->baseString; 442 443 443 444 if (requiredLength > r->capacity) { … … 447 448 if (!r->buf) { 448 449 r->buf = oldBuf; 449 makeNull(); 450 return; 450 return false; 451 451 } 452 452 r->capacity = newCapacity - r->preCapacity; … … 455 455 r->usedCapacity = requiredLength; 456 456 457 m_rep->checkConsistency(); 457 rep->checkConsistency(); 458 return true; 459 } 460 461 void UString::expandCapacity(int requiredLength) 462 { 463 if (!JSC::expandCapacity(m_rep.get(), requiredLength)) 464 makeNull(); 458 465 } 459 466 … … 485 492 } 486 493 487 UString::UString(const char* c) 488 { 489 if (!c) { 490 m_rep = &Rep::null; 491 return; 492 } 493 494 if (!c[0]) { 495 m_rep = &Rep::empty; 496 return; 497 } 494 PassRefPtr<UString::Rep> createRep(const char* c) 495 { 496 if (!c) 497 return &UString::Rep::null; 498 499 if (!c[0]) 500 return &UString::Rep::empty; 498 501 499 502 size_t length = strlen(c); 500 503 UChar* d = allocChars(length); 501 504 if (!d) 502 makeNull();505 return &UString::Rep::null; 503 506 else { 504 507 for (size_t i = 0; i < length; i++) 505 508 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend 506 m_rep = Rep::create(d, static_cast<int>(length)); 507 } 509 return UString::Rep::create(d, static_cast<int>(length)); 510 } 511 512 } 513 514 UString::UString(const char* c) 515 : m_rep(createRep(c)) 516 { 508 517 } 509 518 … … 532 541 else 533 542 m_rep = Rep::createCopying(buffer.data(), buffer.size()); 543 } 544 545 static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize) 546 { 547 RefPtr<UString::Rep> rep = r; 548 549 rep->checkConsistency(); 550 551 int thisSize = rep->size(); 552 int thisOffset = rep->offset; 553 int length = thisSize + tSize; 554 555 // possible cases: 556 if (tSize == 0) { 557 // t is empty 558 } else if (thisSize == 0) { 559 // this is empty 560 rep = UString::Rep::createCopying(tData, tSize); 561 } else if (rep->baseIsSelf() && rep->rc == 1) { 562 // this is direct and has refcount of 1 (so we can just alter it directly) 563 if (!expandCapacity(rep.get(), thisOffset + length)) 564 rep = &UString::Rep::null; 565 if (rep->data()) { 566 copyChars(rep->data() + thisSize, tData, tSize); 567 rep->len = length; 568 rep->_hash = 0; 569 } 570 } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) { 571 // this reaches the end of the buffer - extend it if it's long enough to append to 572 if (!expandCapacity(rep.get(), thisOffset + length)) 573 rep = &UString::Rep::null; 574 if (rep->data()) { 575 copyChars(rep->data() + thisSize, tData, tSize); 576 rep = UString::Rep::create(rep, 0, length); 577 } 578 } else { 579 // this is shared with someone using more capacity, gotta make a whole new string 580 size_t newCapacity = expandedSize(length, 0); 581 UChar* d = allocChars(newCapacity); 582 if (!d) 583 rep = &UString::Rep::null; 584 else { 585 copyChars(d, rep->data(), thisSize); 586 copyChars(d + thisSize, tData, tSize); 587 rep = UString::Rep::create(d, length); 588 rep->capacity = newCapacity; 589 } 590 } 591 592 rep->checkConsistency(); 593 594 return rep.release(); 595 } 596 597 static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t) 598 { 599 RefPtr<UString::Rep> rep = r; 600 601 rep->checkConsistency(); 602 603 int thisSize = rep->size(); 604 int thisOffset = rep->offset; 605 int tSize = static_cast<int>(strlen(t)); 606 int length = thisSize + tSize; 607 608 // possible cases: 609 if (thisSize == 0) { 610 // this is empty 611 rep = createRep(t); 612 } else if (tSize == 0) { 613 // t is empty, we'll just return *this below. 614 } else if (rep->baseIsSelf() && rep->rc == 1) { 615 // this is direct and has refcount of 1 (so we can just alter it directly) 616 expandCapacity(rep.get(), thisOffset + length); 617 UChar* d = rep->data(); 618 if (d) { 619 for (int i = 0; i < tSize; ++i) 620 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 621 rep->len = length; 622 rep->_hash = 0; 623 } 624 } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) { 625 // this string reaches the end of the buffer - extend it 626 expandCapacity(rep.get(), thisOffset + length); 627 UChar* d = rep->data(); 628 if (d) { 629 for (int i = 0; i < tSize; ++i) 630 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 631 rep = UString::Rep::create(rep, 0, length); 632 } 633 } else { 634 // this is shared with someone using more capacity, gotta make a whole new string 635 size_t newCapacity = expandedSize(length, 0); 636 UChar* d = allocChars(newCapacity); 637 if (!d) 638 rep = &UString::Rep::null; 639 else { 640 copyChars(d, rep->data(), thisSize); 641 for (int i = 0; i < tSize; ++i) 642 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 643 rep = UString::Rep::create(d, length); 644 rep->capacity = newCapacity; 645 } 646 } 647 648 rep->checkConsistency(); 649 650 return rep.release(); 534 651 } 535 652 … … 600 717 601 718 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string 602 size_t newCapacity = UString::expandedSize(length, 0);719 size_t newCapacity = expandedSize(length, 0); 603 720 UChar* d = allocChars(newCapacity); 604 721 if (!d) … … 616 733 } 617 734 618 const UString& UString::null() 619 { 620 static UString* n = new UString; // Should be called from main thread at least once to be safely initialized. 621 return *n; 622 } 623 624 UString UString::from(int i) 735 PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i) 625 736 { 626 737 UChar buf[1 + sizeof(i) * 3]; … … 633 744 char minBuf[1 + sizeof(i) * 3]; 634 745 sprintf(minBuf, "%d", INT_MIN); 635 return UString(minBuf);746 return concatenate(rep, minBuf); 636 747 } else { 637 748 bool negative = false; … … 648 759 } 649 760 650 return UString(p, static_cast<int>(end - p)); 651 } 652 653 UString UString::from(unsigned int u) 654 { 655 UChar buf[sizeof(u) * 3]; 656 UChar* end = buf + sizeof(buf) / sizeof(UChar); 657 UChar* p = end; 658 659 if (u == 0) 660 *--p = '0'; 661 else { 662 while (u) { 663 *--p = static_cast<unsigned short>((u % 10) + '0'); 664 u /= 10; 665 } 666 } 667 668 return UString(p, static_cast<int>(end - p)); 669 } 670 671 UString UString::from(long l) 672 { 673 UChar buf[1 + sizeof(l) * 3]; 674 UChar* end = buf + sizeof(buf) / sizeof(UChar); 675 UChar* p = end; 676 677 if (l == 0) 678 *--p = '0'; 679 else if (l == LONG_MIN) { 680 char minBuf[1 + sizeof(l) * 3]; 681 sprintf(minBuf, "%ld", LONG_MIN); 682 return UString(minBuf); 683 } else { 684 bool negative = false; 685 if (l < 0) { 686 negative = true; 687 l = -l; 688 } 689 while (l) { 690 *--p = static_cast<unsigned short>((l % 10) + '0'); 691 l /= 10; 692 } 693 if (negative) 694 *--p = '-'; 695 } 696 697 return UString(p, static_cast<int>(end - p)); 698 } 699 700 UString UString::from(double d) 761 return concatenate(rep, p, static_cast<int>(end - p)); 762 763 } 764 765 PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d) 701 766 { 702 767 // avoid ever printing -NaN, in JS conceptually there is only one NaN value 703 768 if (isnan(d)) 704 return "NaN";769 return concatenate(rep, "NaN"); 705 770 706 771 char buf[80]; … … 761 826 freedtoa(result); 762 827 828 return concatenate(rep, buf); 829 } 830 831 const UString& UString::null() 832 { 833 static UString* n = new UString; // Should be called from main thread at least once to be safely initialized. 834 return *n; 835 } 836 837 UString UString::from(int i) 838 { 839 UChar buf[1 + sizeof(i) * 3]; 840 UChar* end = buf + sizeof(buf) / sizeof(UChar); 841 UChar* p = end; 842 843 if (i == 0) 844 *--p = '0'; 845 else if (i == INT_MIN) { 846 char minBuf[1 + sizeof(i) * 3]; 847 sprintf(minBuf, "%d", INT_MIN); 848 return UString(minBuf); 849 } else { 850 bool negative = false; 851 if (i < 0) { 852 negative = true; 853 i = -i; 854 } 855 while (i) { 856 *--p = static_cast<unsigned short>((i % 10) + '0'); 857 i /= 10; 858 } 859 if (negative) 860 *--p = '-'; 861 } 862 863 return UString(p, static_cast<int>(end - p)); 864 } 865 866 UString UString::from(unsigned int u) 867 { 868 UChar buf[sizeof(u) * 3]; 869 UChar* end = buf + sizeof(buf) / sizeof(UChar); 870 UChar* p = end; 871 872 if (u == 0) 873 *--p = '0'; 874 else { 875 while (u) { 876 *--p = static_cast<unsigned short>((u % 10) + '0'); 877 u /= 10; 878 } 879 } 880 881 return UString(p, static_cast<int>(end - p)); 882 } 883 884 UString UString::from(long l) 885 { 886 UChar buf[1 + sizeof(l) * 3]; 887 UChar* end = buf + sizeof(buf) / sizeof(UChar); 888 UChar* p = end; 889 890 if (l == 0) 891 *--p = '0'; 892 else if (l == LONG_MIN) { 893 char minBuf[1 + sizeof(l) * 3]; 894 sprintf(minBuf, "%ld", LONG_MIN); 895 return UString(minBuf); 896 } else { 897 bool negative = false; 898 if (l < 0) { 899 negative = true; 900 l = -l; 901 } 902 while (l) { 903 *--p = static_cast<unsigned short>((l % 10) + '0'); 904 l /= 10; 905 } 906 if (negative) 907 *--p = '-'; 908 } 909 910 return UString(p, static_cast<int>(end - p)); 911 } 912 913 UString UString::from(double d) 914 { 915 // avoid ever printing -NaN, in JS conceptually there is only one NaN value 916 if (isnan(d)) 917 return "NaN"; 918 919 char buf[80]; 920 int decimalPoint; 921 int sign; 922 923 char* result = dtoa(d, 0, &decimalPoint, &sign, NULL); 924 int length = static_cast<int>(strlen(result)); 925 926 int i = 0; 927 if (sign) 928 buf[i++] = '-'; 929 930 if (decimalPoint <= 0 && decimalPoint > -6) { 931 buf[i++] = '0'; 932 buf[i++] = '.'; 933 for (int j = decimalPoint; j < 0; j++) 934 buf[i++] = '0'; 935 strcpy(buf + i, result); 936 } else if (decimalPoint <= 21 && decimalPoint > 0) { 937 if (length <= decimalPoint) { 938 strcpy(buf + i, result); 939 i += length; 940 for (int j = 0; j < decimalPoint - length; j++) 941 buf[i++] = '0'; 942 buf[i] = '\0'; 943 } else { 944 strncpy(buf + i, result, decimalPoint); 945 i += decimalPoint; 946 buf[i++] = '.'; 947 strcpy(buf + i, result + decimalPoint); 948 } 949 } else if (result[0] < '0' || result[0] > '9') 950 strcpy(buf + i, result); 951 else { 952 buf[i++] = result[0]; 953 if (length > 1) { 954 buf[i++] = '.'; 955 strcpy(buf + i, result + 1); 956 i += length - 1; 957 } 958 959 buf[i++] = 'e'; 960 buf[i++] = (decimalPoint >= 0) ? '+' : '-'; 961 // decimalPoint can't be more than 3 digits decimal given the 962 // nature of float representation 963 int exponential = decimalPoint - 1; 964 if (exponential < 0) 965 exponential = -exponential; 966 if (exponential >= 100) 967 buf[i++] = static_cast<char>('0' + exponential / 100); 968 if (exponential >= 10) 969 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); 970 buf[i++] = static_cast<char>('0' + exponential % 10); 971 buf[i++] = '\0'; 972 } 973 974 freedtoa(result); 975 763 976 return UString(buf); 764 977 } … … 859 1072 UString& UString::append(const UChar* tData, int tSize) 860 1073 { 861 m_rep->checkConsistency(); 862 863 int thisSize = size(); 864 int thisOffset = m_rep->offset; 865 int length = thisSize + tSize; 866 867 // possible cases: 868 if (tSize == 0) { 869 // t is empty 870 } else if (thisSize == 0) { 871 // this is empty 872 m_rep = Rep::createCopying(tData, tSize); 873 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 874 // this is direct and has refcount of 1 (so we can just alter it directly) 875 expandCapacity(thisOffset + length); 876 if (data()) { 877 copyChars(m_rep->data() + thisSize, tData, tSize); 878 m_rep->len = length; 879 m_rep->_hash = 0; 880 } 881 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 882 // this reaches the end of the buffer - extend it if it's long enough to append to 883 expandCapacity(thisOffset + length); 884 if (data()) { 885 copyChars(m_rep->data() + thisSize, tData, tSize); 886 m_rep = Rep::create(m_rep, 0, length); 887 } 888 } else { 889 // this is shared with someone using more capacity, gotta make a whole new string 890 size_t newCapacity = expandedSize(length, 0); 891 UChar* d = allocChars(newCapacity); 892 if (!d) 893 makeNull(); 894 else { 895 copyChars(d, data(), thisSize); 896 copyChars(d + thisSize, tData, tSize); 897 m_rep = Rep::create(d, length); 898 m_rep->capacity = newCapacity; 899 } 900 } 901 902 m_rep->checkConsistency(); 903 1074 m_rep = concatenate(m_rep.release(), tData, tSize); 904 1075 return *this; 905 1076 } … … 907 1078 UString& UString::append(const char* t) 908 1079 { 909 m_rep->checkConsistency(); 910 911 int thisSize = size(); 912 int thisOffset = m_rep->offset; 913 int tSize = static_cast<int>(strlen(t)); 914 int length = thisSize + tSize; 915 916 // possible cases: 917 if (thisSize == 0) { 918 // this is empty 919 *this = t; 920 } else if (tSize == 0) { 921 // t is empty, we'll just return *this below. 922 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 923 // this is direct and has refcount of 1 (so we can just alter it directly) 924 expandCapacity(thisOffset + length); 925 UChar* d = m_rep->data(); 926 if (d) { 927 for (int i = 0; i < tSize; ++i) 928 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 929 m_rep->len = length; 930 m_rep->_hash = 0; 931 } 932 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 933 // this string reaches the end of the buffer - extend it 934 expandCapacity(thisOffset + length); 935 UChar* d = m_rep->data(); 936 if (d) { 937 for (int i = 0; i < tSize; ++i) 938 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 939 m_rep = Rep::create(m_rep, 0, length); 940 } 941 } else { 942 // this is shared with someone using more capacity, gotta make a whole new string 943 size_t newCapacity = expandedSize(length, 0); 944 UChar* d = allocChars(newCapacity); 945 if (!d) 946 makeNull(); 947 else { 948 copyChars(d, data(), thisSize); 949 for (int i = 0; i < tSize; ++i) 950 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 951 m_rep = Rep::create(d, length); 952 m_rep->capacity = newCapacity; 953 } 954 } 955 956 m_rep->checkConsistency(); 957 1080 m_rep = concatenate(m_rep.release(), t); 958 1081 return *this; 959 1082 }
Note:
See TracChangeset
for help on using the changeset viewer.