diff --git a/ChangeLog b/ChangeLog index 629d8d19e..20e403c7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-05-05 Richard Frith-Macdonald + + * Source/GSString.m: + Fix for 64bit systems using TinyString objects ... missing + implementations for common methods were making performance dire. + 2015-05-02 Niels Grewe * Source/GSSet.m diff --git a/Source/GSString.m b/Source/GSString.m index d18099262..4de98a354 100644 --- a/Source/GSString.m +++ b/Source/GSString.m @@ -759,11 +759,43 @@ static void logTinyStringCount(void) fprintf(stderr, "%d tiny strings created\n", tinyStrings); } #endif -@implementation GSTinyString -- (NSUInteger) length + +static int +tsbytes(uintptr_t s, char *buf) { - uintptr_t s = (uintptr_t)self; - return (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + int index; + + for (index = 0; index < length; index++) + { + buf[index] = (char)TINY_STRING_CHAR(s, index); + } + buf[index] = 0; + return index; +} + +@implementation GSTinyString + +- (BOOL) boolValue +{ + char buf[9]; + int count = tsbytes((uintptr_t)self, buf); + int i; + + for (i = 0; i < count; i++) + { + char c = buf[i]; + + if (strchr("123456789yYtT", c) != 0) + { + return YES; + } + if (!isspace(c) && c != '0' && c != '-' && c != '+') + { + break; + } + } + return NO; } - (unichar) characterAtIndex: (NSUInteger)anIndex @@ -784,6 +816,162 @@ static void logTinyStringCount(void) return TINY_STRING_CHAR(s, anIndex); } +- (void) getCharacters: (unichar*)buffer +{ + uintptr_t s = (uintptr_t)self; + int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + int index; + + for (index = 0; index < length; index++) + { + buffer[index] = (unichar)TINY_STRING_CHAR(s, index); + } +} + +- (void) getCharacters: (unichar*)buffer range: (NSRange)aRange +{ + uintptr_t s = (uintptr_t)self; + int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + int index; + int offset; + + GS_RANGE_CHECK(aRange, length); + length = NSMaxRange(aRange); + offset = 0; + for (index = aRange.location; index < length; index++) + { + buffer[offset++] = (unichar)TINY_STRING_CHAR(s, index); + } +} + +- (BOOL) getCString: (char*)buffer + maxLength: (NSUInteger)maxLength + encoding: (NSStringEncoding)encoding +{ + uintptr_t s = (uintptr_t)self; + int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + int index; + + if (buffer == 0) + { + return NO; // Can't fit in here + } + if (NSUnicodeStringEncoding == encoding) + { + maxLength /= 2; + if (maxLength > 1) + { + unichar *buf = (unichar*)buffer; + + if (maxLength <= length) + { + length = maxLength - 1; + } + for (index = 0; index < length; index++) + { + buf[index] = (unichar)TINY_STRING_CHAR(s, index); + } + buf[index] = 0; + return YES; + } + return NO; + } + else if (isByteEncoding(encoding)) + { + if (maxLength > 0) + { + if (maxLength <= length) + { + length = maxLength - 1; + } + for (index = 0; index < length; index++) + { + buffer[index] = (char)TINY_STRING_CHAR(s, index); + } + buffer[index] = 0; + return YES; + } + return NO; + } + return [super getCString: buffer maxLength: maxLength encoding: encoding]; +} + +- (NSUInteger) hash +{ + uintptr_t s = (uintptr_t)self; + int length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; + uint32_t ret = 0; + + if (length > 0) + { + unichar buf[10]; + int index; + + for (index = 0; index < length; index++) + { + buf[index] = (char)TINY_STRING_CHAR(s, index); + } + ret = GSPrivateHash(0, buf, length * sizeof(unichar)); + + /* + * The hash caching in our concrete string classes uses zero to denote + * an empty cache value, so we MUST NOT return a hash of zero. + */ + ret &= 0x0fffffff; + if (ret == 0) + { + ret = 0x0fffffff; + } + } + else + { + ret = 0x0ffffffe; /* Hash for an empty string. */ + } + return ret; +} + +- (int) intValue +{ + char buf[9]; + + tsbytes((uintptr_t)self, buf); + return strtol(buf, 0, 10); +} + +- (NSInteger) integerValue +{ + char buf[9]; + + tsbytes((uintptr_t)self, buf); +#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG + return strtol(buf, 0, 10); +#else + return strtoll(buf, 0, 10); +#endif +} + +- (NSUInteger) length +{ + uintptr_t s = (uintptr_t)self; + return (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK; +} + +- (long long) longLongValue +{ + char buf[9]; + + tsbytes((uintptr_t)self, buf); + return strtoll(buf, 0, 10); +} + +- (const char*) UTF8String +{ + char *buf = GSAutoreleasedBuffer(9); + + tsbytes((uintptr_t)self, buf); + return buf; +} + + (void) load { useTinyStrings = objc_registerSmallObjectClass_np(self, TINY_STRING_MASK); @@ -1557,10 +1745,10 @@ UTF8String_u(GSStr self) static inline BOOL boolValue_c(GSStr self) { - unsigned c = self->_count; + unsigned count = self->_count; unsigned i; - for (i = 0; i < c; i++) + for (i = 0; i < count; i++) { char c = self->_contents.c[i]; @@ -1579,10 +1767,10 @@ boolValue_c(GSStr self) static inline BOOL boolValue_u(GSStr self) { - unsigned c = self->_count; + unsigned count = self->_count; unsigned i; - for (i = 0; i < c; i++) + for (i = 0; i < count; i++) { unichar c = self->_contents.u[i]; @@ -1602,6 +1790,62 @@ boolValue_u(GSStr self) return NO; } +static inline void +intBuf_c(GSStr self, char *buf) +{ + unsigned c = self->_count; + unsigned i = 0; + unsigned j = 0; + + while (i < c && isspace(self->_contents.c[i])) + { + i++; + } + if (i < c) + { + char sign = self->_contents.c[i]; + + if ('+' == sign || '-' == sign) + { + buf[j++] = sign; + i++; + } + } + while (i < c && j < 20 && isdigit(self->_contents.c[i])) + { + buf[j++] = self->_contents.c[i++]; + } + buf[j] = '\0'; +} + +static inline void +intBuf_u(GSStr self, char *buf) +{ + unsigned c = self->_count; + unsigned i = 0; + unsigned j = 0; + + while (i < c && isspace(self->_contents.u[i])) + { + i++; + } + if (i < c) + { + unichar sign = self->_contents.u[i]; + + if ('+' == sign || '-' == sign) + { + buf[j++] = (char)sign; + i++; + } + } + while (i < c && j < 20 && isdigit(self->_contents.u[i])) + { + buf[j++] = (char)self->_contents.u[i++]; + } + buf[j] = '\0'; +} + static inline BOOL canBeConvertedToEncoding_c(GSStr self, NSStringEncoding enc) { @@ -2621,56 +2865,6 @@ getCStringE_u(GSStr self, char *buffer, unsigned int maxLength, } } -static inline int -intValue_c(GSStr self) -{ - const char *ptr = (const char*)self->_contents.c; - const char *end = ptr + self->_count; - - while (ptr < end && isspace(*ptr)) - { - ptr++; - } - if (ptr == end) - { - return 0; - } - else - { - unsigned int l = (end - ptr) < 32 ? (end - ptr) : 31; - char buf[32]; - - memcpy(buf, ptr, l); - buf[l] = '\0'; - return atol((const char*)buf); - } -} - -static inline int -intValue_u(GSStr self) -{ - const unichar *ptr = self->_contents.u; - const unichar *end = ptr + self->_count; - - while (ptr < end && isspace(*ptr)) - { - ptr++; - } - if (ptr == end) - { - return 0; - } - else - { - unsigned int l = (end - ptr) < 32 ? (end - ptr) : 31; - unsigned char buf[32]; - unsigned char *b = buf; - - GSFromUnicode(&b, &l, ptr, l, internalEncoding, 0, GSUniTerminate); - return atol((const char*)buf); - } -} - static inline BOOL isEqual_c(GSStr self, id anObject) { @@ -3666,7 +3860,22 @@ agree, create a new GSCInlineString otherwise. - (int) intValue { - return intValue_c((GSStr)self); + char buf[24]; + + intBuf_c((GSStr)self, buf); + return strtol(buf, 0, 10); +} + +- (NSInteger) integerValue +{ + char buf[24]; + + intBuf_c((GSStr)self, buf); +#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG + return strtol(buf, 0, 10); +#else + return strtoll(buf, 0, 10); +#endif } - (BOOL) isEqual: (id)anObject @@ -3689,6 +3898,14 @@ agree, create a new GSCInlineString otherwise. return cStringLength_c((GSStr)self, encoding); } +- (long long) longLongValue +{ + char buf[24]; + + intBuf_c((GSStr)self, buf); + return strtoll(buf, 0, 10); +} + - (const char*) lossyCString { return lossyCString_c((GSStr)self); @@ -4020,7 +4237,22 @@ agree, create a new GSCInlineString otherwise. - (int) intValue { - return intValue_u((GSStr)self); + char buf[24]; + + intBuf_u((GSStr)self, buf); + return strtol(buf, 0, 10); +} + +- (NSInteger) integerValue +{ + char buf[24]; + + intBuf_u((GSStr)self, buf); +#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG + return strtol(buf, 0, 10); +#else + return strtoll(buf, 0, 10); +#endif } - (BOOL) isEqual: (id)anObject @@ -4043,6 +4275,14 @@ agree, create a new GSCInlineString otherwise. return cStringLength_u((GSStr)self, encoding); } +- (long long) longLongValue +{ + char buf[24]; + + intBuf_u((GSStr)self, buf); + return strtoll(buf, 0, 10); +} + - (const char*) lossyCString { return lossyCString_u((GSStr)self); @@ -4832,10 +5072,28 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException); - (int) intValue { + char buf[24]; + if (_flags.wide == 1) - return intValue_u((GSStr)self); + intBuf_u((GSStr)self, buf); else - return intValue_c((GSStr)self); + intBuf_c((GSStr)self, buf); + return strtol(buf, 0, 10); +} + +- (NSInteger) integerValue +{ + char buf[24]; + + if (_flags.wide == 1) + intBuf_u((GSStr)self, buf); + else + intBuf_c((GSStr)self, buf); +#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG + return strtol(buf, 0, 10); +#else + return strtoll(buf, 0, 10); +#endif } - (BOOL) isEqual: (id)anObject @@ -4867,6 +5125,17 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException); return cStringLength_c((GSStr)self, encoding); } +- (long long) longLongValue +{ + char buf[24]; + + if (_flags.wide == 1) + intBuf_u((GSStr)self, buf); + else + intBuf_c((GSStr)self, buf); + return strtoll(buf, 0, 10); +} + - (const char*) lossyCString { if (_flags.wide == 1) @@ -5619,11 +5888,30 @@ literalIsEqual(NXConstantString *self, id anObject) return literalIsEqual(self, other); } +- (int) intValue +{ + return strtol((const char*)nxcsptr, 0, 10); +} + +- (NSInteger) integerValue +{ +#if GS_SIZEOF_VOIDP == GS_SIZEOF_LONG + return strtol((const char*)nxcsptr, 0, 10); +#else + return strtoll((const char*)nxcsptr, 0, 10); +#endif +} + - (NSUInteger) length { return lengthUTF8((const uint8_t*)nxcsptr, nxcslen, 0, 0); } +- (long long) longLongValue +{ + return strtoll((const char*)nxcsptr, 0, 10); +} + - (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet options: (NSUInteger)mask range: (NSRange)aRange