4
Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
7
Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
9
This file is part of libFoundation.
11
Permission to use, copy, modify, and distribute this software and its
12
documentation for any purpose and without fee is hereby granted, provided
13
that the above copyright notice appear in all copies and that both that
14
copyright notice and this permission notice appear in supporting
17
We disclaim all warranties with regard to this software, including all
18
implied warranties of merchantability and fitness, in no event shall
19
we be liable for any special, indirect or consequential damages or any
20
damages whatsoever resulting from loss of use, data or profits, whether in
21
an action of contract, negligence or other tortious action, arising out of
22
or in connection with the use or performance of this software.
29
#include <Foundation/common.h>
30
#include <Foundation/NSArray.h>
31
#include <Foundation/NSDictionary.h>
32
#include <Foundation/NSData.h>
33
#include <Foundation/NSCoder.h>
34
#include <Foundation/NSAutoreleasePool.h>
35
#include <Foundation/NSException.h>
36
#include <Foundation/exceptions/StringExceptions.h>
37
#include <Foundation/exceptions/GeneralExceptions.h>
39
#include <Foundation/NSCharacterSet.h>
40
#include <Foundation/NSString.h>
41
#include <Foundation/NSConcreteString.h>
43
#include <extensions/objc-runtime.h>
45
#define COLLECT_STRING_CLUSTER_STATISTICS 0
46
#define PERF_8BIT_USE_OPT_COMPARE 1
47
#define PERF_SHTIN_USE_OWN_HASH 1
48
#define PERF_SHTIN_USE_OWN_EQUAL 1
49
#define PERF_SHTIN_USE_OWN_GETCHARS 1
51
static Class NS8BitStringClass = Nil;
52
static Class NSMutable8BitStringClass = Nil;
53
static Class NSShtInline8BitStringClass = Nil;
54
static Class NSInline8BitStringClass = Nil;
55
static Class NSDataClass = Nil;
56
static Class NSStringClass = Nil;
58
#if COLLECT_STRING_CLUSTER_STATISTICS
59
static unsigned int NS8BitString_dealloc_count = 0;
60
static unsigned int NSInline8BitString_dealloc_count = 0;
61
static unsigned int NSInline8BitString_total_len = 0;
62
static unsigned int NSShortInline8BitString_dealloc_count = 0;
63
static unsigned int NSShortInline8BitString_total_len = 0;
64
static unsigned int NSNonOwned8BitString_dealloc_count = 0;
65
static unsigned int NSNonOwned8BitString_total_len = 0;
66
static unsigned int NSOwned8BitString_dealloc_count = 0;
67
static unsigned int NSOwned8BitString_total_len = 0;
68
static unsigned int NSNonOwnedOpen8BitString_dealloc_count = 0;
69
static unsigned int NSNonOwnedOpen8BitString_total_len = 0;
70
static unsigned int NSOwnedOpen8BitString_dealloc_count = 0;
71
static unsigned int NSOwnedOpen8BitString_total_len = 0;
72
static unsigned int NSRange8BitString_dealloc_count = 0;
73
static unsigned int NSRange8BitString_total_len = 0;
75
@implementation NSString(ClusterStatistics)
77
+ (void)printStatistics
80
"NSString class cluster statistics:\n"
83
" NSInline8BitString: %d\n"
84
" NSShortInline8BitString: %d\n"
85
" NSNonOwned8BitString: %d\n"
86
" NSOwned8BitString: %d\n"
87
" NSOwnedOpen8BitString: %d\n"
88
" NSNonOwnedOpen8BitString: %d\n"
89
" NSRange8BitString: %d\n"
90
" avg len (dealloc statistics):\n"
92
" NSInline8BitString: %d\n"
93
" NSShortInline8BitString: %d\n"
94
" NSNonOwned8BitString: %d\n"
95
" NSOwned8BitString: %d\n"
96
" NSOwnedOpen8BitString: %d\n"
97
" NSNonOwnedOpen8BitString: %d\n"
98
" NSRange8BitString: %d\n"
100
NS8BitString_dealloc_count,
101
NSInline8BitString_dealloc_count,
102
NSShortInline8BitString_dealloc_count,
103
NSNonOwned8BitString_dealloc_count,
104
NSOwned8BitString_dealloc_count,
105
NSOwnedOpen8BitString_dealloc_count,
106
NSNonOwnedOpen8BitString_dealloc_count,
107
NSRange8BitString_dealloc_count,
108
NSInline8BitString_dealloc_count
109
? NSInline8BitString_total_len / NSInline8BitString_dealloc_count
111
NSShortInline8BitString_dealloc_count
112
? NSShortInline8BitString_total_len /
113
NSShortInline8BitString_dealloc_count
115
NSNonOwned8BitString_dealloc_count
116
? NSNonOwned8BitString_total_len/NSNonOwned8BitString_dealloc_count
118
NSOwned8BitString_dealloc_count
119
? NSOwned8BitString_total_len / NSOwned8BitString_dealloc_count
121
NSOwnedOpen8BitString_dealloc_count
122
? NSOwnedOpen8BitString_total_len /
123
NSOwnedOpen8BitString_dealloc_count
125
NSNonOwnedOpen8BitString_dealloc_count
126
? NSNonOwnedOpen8BitString_total_len /
127
NSNonOwnedOpen8BitString_dealloc_count
129
NSRange8BitString_dealloc_count
130
? NSRange8BitString_total_len / NSRange8BitString_dealloc_count
134
- (void)printStatistics
136
[NSString printStatistics];
140
#endif /* COLLECT_STRING_CLUSTER_STATISTICS */
142
@implementation NS8BitString
146
NS8BitStringClass = [NS8BitString class];
147
NSMutable8BitStringClass = [NSMutable8BitStringClass class];
148
NSShtInline8BitStringClass = [NSShortInline8BitString class];
149
NSInline8BitStringClass = [NSInline8BitStringClass class];
150
NSDataClass = [NSData class];
151
NSStringClass = [NSString class];
154
#if COLLECT_STRING_CLUSTER_STATISTICS
157
NS8BitString_dealloc_count++;
162
/* Accessing characters */
164
- (void)getCharacters:(unichar *)buffer
166
register unsigned int i = 0, l;
167
register unsigned char *bytes;
169
if ((l = [self cStringLength]) == 0)
172
bytes = [self __compact8BitBytes];
173
for (i = 0; i < l; i++)
174
buffer[i] = (unichar)bytes[i];
176
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
178
register unsigned int i = 0;
179
unsigned char *bytes;
181
if (aRange.location + aRange.length > [self cStringLength]) {
182
[[[IndexOutOfRangeException alloc]
183
initWithFormat:@"range (%d,%d) in string %x of length %d",
184
aRange.location, aRange.length, self, [self cStringLength]]
188
bytes = [self __compact8BitBytes];
189
for (i = 0; i < aRange.length; i++)
190
buffer[i] = bytes[i];
193
/* Dividing strings */
195
- (NSString *)substringWithRange:(NSRange)aRange
197
[self subclassResponsibility:_cmd];
201
/* Finding characters and substrings */
203
- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
204
options:(unsigned int)mask range:(NSRange)aRange
206
// ENCODINGS - this code applies to the system's default encoding
209
IMP imp = [aSet methodForSelector:@selector(characterIsMember:)];
210
unsigned char *bytes = [self __compact8BitBytes];
212
if (NSMaxRange(aRange) > [self cStringLength]) {
213
[[[IndexOutOfRangeException alloc]
214
initWithFormat:@"range %@ not in string 0x%08x of length %d",
215
NSStringFromRange(aRange), self, [self cStringLength]]
219
if (mask & NSBackwardsSearch) {
220
for (i = aRange.length - 1; i >= aRange.location; i--) {
221
unichar c = bytes[i];
223
if ((*imp)(aSet, @selector(characterIsMember:), c) ||
224
((mask & NSCaseInsensitiveSearch) &&
226
(*imp)(aSet, @selector(characterIsMember:), toupper(c))) ||
228
(*imp)(aSet, @selector(characterIsMember:), tolower(c))))
230
return NSMakeRange(i, 1);
235
unsigned max = NSMaxRange(aRange);
236
for (i = aRange.location; i < max; i++) {
237
unichar c = bytes[i];
239
if ((*imp)(aSet, @selector(characterIsMember:), c) ||
240
((mask & NSCaseInsensitiveSearch) &&
242
(*imp)(aSet, @selector(characterIsMember:), toupper(c))) ||
244
(*imp)(aSet, @selector(characterIsMember:), tolower(c))))
246
return NSMakeRange(i, 1);
251
return NSMakeRange(NSNotFound, 0);
254
- (NSRange)rangeOfString:(NSString*)aString
255
options:(unsigned int)mask range:(NSRange)aRange
257
// ENCODINGS - this code applies to the system's default encoding
259
unsigned char *mbytes;
260
unsigned char *abytes;
263
if (![aString isKindOfClass:NS8BitStringClass] &&
264
![aString isKindOfClass:NSMutable8BitStringClass])
265
return [super rangeOfString:aString options:mask range:aRange];
267
if ((aRange.location + aRange.length) > [self cStringLength]) {
268
[[[IndexOutOfRangeException alloc]
269
initWithFormat:@"range (%d,%d) in string %x of length %d",
270
aRange.location, aRange.length, self, [self cStringLength]]
274
mbytes = [self __compact8BitBytes] + aRange.location;
275
abytes = [(id)aString __compact8BitBytes];
276
a = [aString cStringLength];
278
if ((a == 0) || (aRange.length < a))
279
return NSMakeRange(0, 0);
281
if (mask & NSAnchoredSearch) {
282
range.location = aRange.location +
283
((mask & NSBackwardsSearch) ? aRange.length - a : 0);
286
if ([self compare:aString options:mask range:range] == NSOrderedSame)
289
return NSMakeRange(0,0);
292
if (mask & NSBackwardsSearch) {
293
if (mask & NSCaseInsensitiveSearch) {
294
/* Backward case insensitive */
298
cf = islower(abytes[0]) ? toupper(abytes[0]) : abytes[0];
300
for (n = aRange.length-a; n >= 0; n--) {
302
islower(mbytes[n]) ? toupper(mbytes[n]) : mbytes[n];
303
unsigned char ca = cf;
308
for (i = 1; i < a; i++) {
309
cm = islower(mbytes[n+i]) ?
310
toupper(mbytes[n+i]) : mbytes[n+i];
311
ca = islower(abytes[i]) ? toupper(abytes[i]) : abytes[i];
316
range.location = aRange.location + n;
323
/* Backward case sensitive */
325
for (n = (aRange.length - a); n >= 0; n--) {
328
if (mbytes[n] != abytes[0])
330
for (i = 1; i < a; i++)
331
if (mbytes[n+i] != abytes[i])
334
range.location = aRange.location + n;
342
if (mask & NSCaseInsensitiveSearch) {
343
/* Forward case insensitive */
347
cf = islower(abytes[0]) ? toupper(abytes[0]) : abytes[0];
349
for (n = 0; n + a <= aRange.length; n++) {
350
unsigned char cm, ca;
353
cm = islower(mbytes[n]) ? toupper(mbytes[n]) : mbytes[n];
358
for (i = 1; i < a; i++) {
359
cm = islower(mbytes[n+i]) ?
360
toupper(mbytes[n+i]) : mbytes[n+i];
361
ca = islower(abytes[i]) ? toupper(abytes[i]) : abytes[i];
366
range.location = aRange.location + n;
373
/* Forward case sensitive */
376
for (n = 0; (n + a) <= aRange.length; n++) {
379
if (mbytes[n] != abytes[0])
381
for (i = 1; i < a; i++)
382
if (mbytes[n+i] != abytes[i])
385
range.location = aRange.location + n;
393
range.location = range.length = 0;
397
- (NSComparisonResult)compare:(NSString *)aString
398
options:(unsigned int)mask range:(NSRange)aRange
400
// ENCODINGS - this code applies to the system's default encoding
401
register unsigned char *mbytes;
402
register unsigned char *abytes;
403
unsigned int i, n, a;
405
#if PERF_8BIT_USE_OPT_COMPARE /* optimized */
406
register Class clazz;
408
if (aString == nil) /* TODO: hh: AFAIK nil is not allowed in Cocoa? */
409
return NSOrderedDescending;
410
else if (aString == self)
411
return NSOrderedSame;
413
for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
414
if (clazz == NS8BitStringClass || clazz == NSMutable8BitStringClass) {
420
return [super compare:aString options:mask range:aRange];
422
if (![aString isKindOfClass:NS8BitStringClass] &&
423
![aString isKindOfClass:NSMutable8BitStringClass]) {
424
return [super compare:aString options:mask range:aRange];
428
if (aRange.location + aRange.length > [self cStringLength]) {
429
[[[IndexOutOfRangeException alloc]
430
initWithFormat:@"range (%d,%d) in string %x of length %d",
431
aRange.location, aRange.length, self, [self cStringLength]]
435
mbytes = [self __compact8BitBytes] + aRange.location;
436
abytes = [(id)aString __compact8BitBytes];
438
a = [aString cStringLength];
439
n = MIN(a, aRange.length);
441
if (mask & NSCaseInsensitiveSearch) {
442
for (i = 0; i < n; i++) {
443
register unsigned char cm =
444
islower(mbytes[i]) ? toupper(mbytes[i]):mbytes[i];
445
register unsigned char ca =
446
islower(abytes[i]) ? toupper(abytes[i]):abytes[i];
449
return NSOrderedAscending;
451
return NSOrderedDescending;
455
for (i = 0; i < n; i++) {
456
if (mbytes[i] < abytes[i])
457
return NSOrderedAscending;
458
if (mbytes[i] > abytes[i])
459
return NSOrderedDescending;
463
if (aRange.length < a)
464
return NSOrderedAscending;
465
if (aRange.length > a)
466
return NSOrderedDescending;
468
return NSOrderedSame;
473
static Class LastClass = Nil;
474
static unsigned char *(*compact)(id, SEL) = NULL;
475
static unsigned int (*cstrlen)(id, SEL) = NULL;
476
register unsigned char *bytes;
477
register unsigned hash = 0, hash2;
480
#if GNU_RUNTIME /* selector caching */
481
if (LastClass != *(id *)self) {
482
LastClass = *(id *)self;
483
compact = (void *)method_get_imp(class_get_instance_method(LastClass,
484
@selector(__compact8BitBytes)));
485
cstrlen = (void *)method_get_imp(class_get_instance_method(LastClass,
486
@selector(cStringLength)));
488
bytes = compact(self, NULL /* dangerous? */);
489
n = cstrlen(self, NULL /* dangerous? */);
491
bytes = [self __compact8BitBytes];
492
n = [self cStringLength];
495
for (i = 0; i < n; i++) {
497
// UNICODE - must use a for independent of composed characters
499
if ((hash2 = hash & 0xf0000000))
500
hash ^= (hash2 >> 24) ^ hash2;
506
/* Getting a shared prefix */
508
- (NSString *)commonPrefixWithString:(NSString*)aString
509
options:(unsigned int)mask
511
// ENCODINGS - this code applies to the system's default encoding
512
NSRange range = {0, 0};
513
unsigned char *mbytes;
514
unsigned char *abytes;
517
if (![aString isKindOfClass:NS8BitStringClass] &&
518
![aString isKindOfClass:NSMutable8BitStringClass]) {
519
return [super commonPrefixWithString:aString options:mask];
522
mLen = [self cStringLength];
523
aLen = [aString length];
524
mbytes = [self __compact8BitBytes];
525
abytes = [(NS8BitString *)aString __compact8BitBytes];
527
for (i = 0; (i < mLen) && (i < aLen); i++) {
528
unsigned char c1 = mbytes[i];
529
unsigned char c2 = abytes[i];
531
if (mask & NSCaseInsensitiveSearch) {
540
return [self substringWithRange:range];
545
- (NSString *)capitalizedString
547
// ENCODINGS - this code applies to the system's default encoding
550
int length = [self cStringLength];
551
unsigned char* bytes = [self __compact8BitBytes];
552
unsigned char* chars = MallocAtomic(sizeof(unichar)*(length+1));
554
for (i = 0; i < length; i++) {
555
unsigned char c = bytes[i];
561
chars[i] = islower(c) ? toupper(c) : c;
565
chars[i] = isupper(c) ? tolower(c) : c;
569
return AUTORELEASE([[NSOwned8BitString alloc]
570
initWithCString:chars length:length copy:NO]);
573
- (NSString *)lowercaseString
575
// ENCODINGS - this code applies to the system's default encoding
577
int length = [self cStringLength];
578
unsigned char *bytes = [self __compact8BitBytes];
579
unsigned char *chars = MallocAtomic(sizeof(unichar)*(length+1));
581
for (i = 0; i < length; i++) {
582
register unsigned char c = bytes[i];
583
chars[i] = isupper(c) ? tolower(c) : c;
587
return AUTORELEASE([[NSOwned8BitString alloc]
588
initWithCString:chars length:length copy:NO]);
591
- (NSString *)uppercaseString
593
// ENCODINGS - this code applies to the system's default encoding
595
int length = [self cStringLength];
596
unsigned char *bytes = [self __compact8BitBytes];
597
unsigned char *chars = MallocAtomic(sizeof(unichar)*(length+1));
599
for (i = 0; i < length; i++) {
600
register unsigned char c = bytes[i];
601
chars[i] = islower(c) ? toupper(c) : c;
606
return AUTORELEASE([[NSOwned8BitString alloc]
607
initWithCString:chars length:length copy:NO]);
610
/* Working with C strings */
612
- (void)getCString:(char *)buffer maxLength:(unsigned int)maxLength
613
range:(NSRange)aRange remainingRange:(NSRange*)leftoverRange
615
unsigned char* bytes = [self __compact8BitBytes];
616
unsigned int toMove = MIN(maxLength, aRange.length);
617
unsigned int cLength = [self cStringLength];
619
if (aRange.location + aRange.length > cLength) {
620
[[[IndexOutOfRangeException alloc]
621
initWithFormat:@"range (%d,%d) in string %x of length %d",
622
aRange.location, aRange.length, self, cLength] raise];
626
leftoverRange->location = aRange.location + toMove;
627
leftoverRange->length = cLength - leftoverRange->location;
629
memcpy(buffer, bytes + aRange.location, toMove);
630
if (toMove < maxLength)
631
buffer[toMove] = '\0';
634
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
636
// UNICODE - remove this
638
data = [self dataUsingEncoding:[NSString defaultCStringEncoding]];
639
return writeToFile(path, data, flag);
642
- (Class)classForCoder
644
return NS8BitStringClass;
647
- (void)encodeWithCoder:(NSCoder*)aCoder
649
const unsigned char* bytes = [self __compact8BitBytes];
650
int length = [self cStringLength];
652
[aCoder encodeValueOfObjCType:@encode(int) at:&length];
653
[aCoder encodeArrayOfObjCType:@encode(char) count:length at:bytes];
656
- (id)initWithCoder:(NSCoder*)aDecoder
658
unsigned char *bytes;
661
RELEASE(self); self = nil;
663
[aDecoder decodeValueOfObjCType:@encode(int) at:&length];
664
bytes = MallocAtomic (length + 1);
665
[aDecoder decodeArrayOfObjCType:@encode(char) count:length at:bytes];
666
bytes[length] = '\0';
667
return [[NSOwned8BitString alloc] initWithCString:bytes length:length copy:NO];
670
- (NSString *)stringRepresentation
672
const unsigned char *cString;
675
cString = [self __compact8BitBytes];
676
length = [self cStringLength];
678
if (cString == NULL) return @"\"\"";
679
if (length == 0) return @"\"\"";
680
if (cString[0] == '\0') return @"\"\"";
682
/* Check if the string can be parsed as a STRING token by the property list
683
parser. Otherwise we must enclose it in double quotes. */
684
if (lf_isPlistBreakChar(cString[0])) {
685
return lf_quoteString(cString, length);
688
for(i = 1; i < length; i++) {
689
if (lf_isPlistBreakChar(cString[i]))
690
return lf_quoteString(cString, length);
696
- (id)copyWithZone:(NSZone*)zone
698
register Class clazz;
701
if (NSShouldRetainWithZone(self, zone))
704
length = [self cStringLength];
707
? NSShtInline8BitStringClass
708
: NSInline8BitStringClass;
710
return [[clazz allocForCapacity:length zone:zone]
711
initWithCString:[self __compact8BitBytes] length:length];
714
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
715
allowLossyConversion:(BOOL)flag;
718
if (encoding == [NSStringClass defaultCStringEncoding]) {
720
unsigned char *buf = NULL;
722
len = [self cStringLength];
723
buf = NSZoneMalloc(NULL, sizeof(unsigned char) * len + 1);
724
[self getCString:buf];
726
return [NSDataClass dataWithBytesNoCopy:buf length:strlen(buf)];
728
if (encoding == NSASCIIStringEncoding) {
729
register unsigned len = [self cStringLength];
731
register unsigned char *buf;
733
buf = NSZoneMalloc(NULL, sizeof(char) * len + 1);
736
[self getCString:buf];
738
/* check for strict ASCII */
739
for (i = 0; i < len; i++)
740
if (buf[i] > 127) return nil;
742
return [NSDataClass dataWithBytesNoCopy:buf length:len];
745
return [super dataUsingEncoding:encoding allowLossyConversion:flag];
748
- (id)mutableCopyWithZone:(NSZone*)zone
750
return [[NSMutableSimple8BitString allocWithZone:zone]
751
initWithCString:[self __compact8BitBytes]
752
length:[self cStringLength] copy:YES];
755
@end /* NS8BitString */
758
* Null terminated CString containing characters inline
761
@implementation NSInline8BitString /* final */
763
+ (id)allocForCapacity:(unsigned int)capacity zone:(NSZone *)zone
765
NSInline8BitString *str = NSAllocateObject(self, capacity, zone);
772
if (self->cLength != -1) {
773
[[[InvalidUseOfMethodException alloc] initWithFormat:
774
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
778
self->cString[0] = 0;
782
- (id)initWithCString:(const char*)byteString length:(unsigned int)length
784
if (self->cLength != -1) {
785
[[[InvalidUseOfMethodException alloc] initWithFormat:
786
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
789
self->cLength = length;
790
memcpy(self->cString, byteString, length);
791
self->cString[length] = 0;
794
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
796
/* it must be ensured that char values are below 256 by the cluster ! */
798
if (self->cLength != -1) {
799
[[[InvalidUseOfMethodException alloc] initWithFormat:
800
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
804
for (i = 0; i < length; i++)
805
self->cString[i] = chars[i];
806
self->cString[i] = '\0';
811
#if COLLECT_STRING_CLUSTER_STATISTICS
814
NSInline8BitString_dealloc_count++;
815
NSInline8BitString_total_len += self->cLength == -1 ? 0 : self->cLength;
820
- (const char *)cString
822
return self->cString;
825
- (unsigned int)cStringLength
827
return (self->cLength == -1) ? 0 : self->cLength;
830
- (unsigned int)length
832
return (self->cLength == -1) ? 0 : self->cLength;
835
- (unichar)characterAtIndex:(unsigned int)index
837
if (self->cLength == -1 || (int)index >= self->cLength) {
838
[[[IndexOutOfRangeException alloc]
839
initWithFormat:@"index %d out of range in string %x of length %d",
840
index, self, self->cLength] raise];
843
return self->cString[index];
846
- (NSString *)substringWithRange:(NSRange)aRange
848
if (aRange.location + aRange.length > (unsigned)self->cLength) {
849
[[[IndexOutOfRangeException alloc]
850
initWithFormat:@"range (%d,%d) in string %x of length %d",
851
aRange.location, aRange.length, self, cLength] raise];
853
if (aRange.length == 0)
856
return AUTORELEASE([[NSRange8BitString alloc]
858
bytes:(self->cString + aRange.location)
859
length:aRange.length]);
862
- (char *)__compact8BitBytes
864
return self->cString;
869
register unsigned char *bytes;
870
register unsigned hash = 0, hash2;
873
bytes = self->cString;
874
n = (self->cLength == -1) ? 0 : self->cLength;
876
for (i = 0; i < n; i++) {
878
// UNICODE - must use a for independent of composed characters
880
if ((hash2 = hash & 0xf0000000))
881
hash ^= (hash2 >> 24) ^ hash2;
887
@end /* NSInline8BitString */
889
@implementation NSShortInline8BitString /* final */
891
+ (id)allocForCapacity:(unsigned int)capacity zone:(NSZone*)zone
893
NSShortInline8BitString *str = NSAllocateObject(self, capacity, zone);
900
if (self->cLength != 255) {
901
[[[InvalidUseOfMethodException alloc] initWithFormat:
902
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
906
self->cString[0] = 0;
910
- (id)initWithCString:(const char*)byteString length:(unsigned int)length
912
if (self->cLength != 255) {
913
[[[InvalidUseOfMethodException alloc] initWithFormat:
914
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
917
self->cLength = length;
918
memcpy(self->cString, byteString, length);
919
self->cString[length] = 0;
922
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)length
924
/* it must be ensured that char values are below 256 by the cluster ! */
926
if (self->cLength != 255) {
927
[[[InvalidUseOfMethodException alloc] initWithFormat:
928
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
932
for (i = 0; i < length; i++)
933
self->cString[i] = chars[i];
934
self->cString[i] = '\0';
939
#if COLLECT_STRING_CLUSTER_STATISTICS
942
NSShortInline8BitString_dealloc_count++;
943
NSShortInline8BitString_total_len +=
944
self->cLength == 255 ? 0 : self->cLength;
949
- (const char *)cString
951
return self->cString;
954
- (unsigned int)cStringLength
956
return (self->cLength == 255) ? 0 : self->cLength;
959
- (unsigned int)length
961
return (self->cLength == 255) ? 0 : self->cLength;
964
- (unichar)characterAtIndex:(unsigned int)index
966
if ((self->cLength == 255) || (index >= self->cLength)) {
967
[[[IndexOutOfRangeException alloc]
968
initWithFormat:@"index %d out of range in string %x of length %d",
969
index, self, self->cLength] raise];
972
return self->cString[index];
975
#if PERF_SHTIN_USE_OWN_GETCHARS
976
- (void)getCharacters:(unichar *)buffer
978
register signed short i;
981
if ((i == 255) || (i == 0)) /* empty string */
984
for (i--; i >= 0; i--)
985
buffer[i] = (unichar)(self->cString[i]);
987
- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange
989
register unsigned int i = 0, l;
992
l = i + aRange.length;
993
if (l > ((self->cLength == 255) ? 0 : self->cLength)) {
994
[[[IndexOutOfRangeException alloc]
995
initWithFormat:@"range (%d,%d) in string %x of length %d",
996
aRange.location, aRange.length, self, [self length]] raise];
1000
buffer[i] = (unichar)(self->cString[i]);
1004
- (NSString *)substringWithRange:(NSRange)aRange
1006
if (aRange.location + aRange.length > self->cLength)
1007
[[[IndexOutOfRangeException alloc]
1008
initWithFormat:@"range (%d,%d) in string %x of length %d",
1009
aRange.location, aRange.length, self, cLength] raise];
1011
if (aRange.length == 0)
1014
return AUTORELEASE([[NSRange8BitString alloc]
1016
bytes:(self->cString + aRange.location)
1017
length:aRange.length]);
1020
- (char *)__compact8BitBytes
1022
return self->cString;
1025
- (NSComparisonResult)compare:(NSString *)aString
1026
options:(unsigned int)mask range:(NSRange)aRange
1028
// ENCODINGS - this code applies to the system's default encoding
1029
register unsigned char *mbytes, *abytes;
1030
register Class clazz;
1031
unsigned int i, n, a;
1033
#if 1 /* optimized */
1034
if (aString == nil) /* TODO: hh: AFAIK nil is not allowed in Cocoa? */
1035
return NSOrderedDescending;
1036
else if (aString == self)
1037
return NSOrderedSame;
1039
for (clazz = *(id *)aString; clazz; clazz = class_get_super_class(clazz)) {
1040
if (clazz == NS8BitStringClass || clazz == NSMutable8BitStringClass) {
1046
return [super compare:aString options:mask range:aRange];
1048
if (![aString isKindOfClass:NS8BitStringClass] &&
1049
![aString isKindOfClass:NSMutable8BitStringClass]) {
1050
return [super compare:aString options:mask range:aRange];
1054
if ((aRange.location + aRange.length) >
1055
((self->cLength == 255) ? 0 : self->cLength)) {
1056
[[[IndexOutOfRangeException alloc]
1057
initWithFormat:@"range (%d,%d) in string %x of length %d",
1058
aRange.location, aRange.length, self, [self cStringLength]]
1062
mbytes = self->cString + aRange.location;
1063
abytes = [(id)aString __compact8BitBytes];
1065
a = [aString cStringLength];
1066
n = MIN(a, aRange.length);
1068
if (mask & NSCaseInsensitiveSearch) {
1069
for (i = 0; i < n; i++) {
1070
register unsigned char cm =
1071
islower(mbytes[i]) ? toupper(mbytes[i]):mbytes[i];
1072
register unsigned char ca =
1073
islower(abytes[i]) ? toupper(abytes[i]):abytes[i];
1076
return NSOrderedAscending;
1078
return NSOrderedDescending;
1082
for (i = 0; i < n; i++) {
1083
if (mbytes[i] < abytes[i])
1084
return NSOrderedAscending;
1085
if (mbytes[i] > abytes[i])
1086
return NSOrderedDescending;
1090
if (aRange.length < a)
1091
return NSOrderedAscending;
1092
if (aRange.length > a)
1093
return NSOrderedDescending;
1095
return NSOrderedSame;
1098
#if PERF_SHTIN_USE_OWN_HASH
1102
according to Valgrind this takes 3.13% of the runtime, can this be
1103
further optimized without breaking dictionary performance due to
1106
register unsigned char *bytes;
1107
register unsigned hash = 0, hash2;
1110
bytes = self->cString;
1111
n = (self->cLength == 255) ? 0 : self->cLength;
1113
for (i = 0; i < n; i++) {
1115
// UNICODE - must use a for independent of composed characters
1117
if ((hash2 = hash & 0xf0000000))
1118
hash ^= (hash2 >> 24) ^ hash2;
1125
#if PERF_SHTIN_USE_OWN_EQUAL
1126
- (BOOL)isEqual:(id)aString
1128
register unsigned char *mbytes, *abytes;
1129
register Class clazz;
1130
unsigned int i, n, a;
1133
if (self == aString)
1135
else if (aString == nil)
1139
if (*(id *)aString == *(id *)self) { /* exactly the same class */
1140
i = 1; /* is NSString subclass */
1141
n = 1; /* is 8-bit string subclass */
1142
a = 1; /* is exactly the same string class */
1146
for (clazz=*(id *)aString; clazz; clazz=class_get_super_class(clazz)) {
1147
if (clazz==NS8BitStringClass || clazz==NSMutable8BitStringClass) {
1148
i = 1; // is NSString subclass
1149
n = 1; // is 8-bit string subclass
1152
if (clazz == NSStringClass) {
1153
i = 1; // is NSString subclass
1154
n = 0; // is not an 8-bit string subclass
1158
if (i == 0) // not a NSString subclass
1161
range.length = (self->cLength == 255) ? 0 : self->cLength;
1162
if (n == 0) { // is not an 8-bit string subclass, use compare
1164
return [self compare:aString options:0 range:range] == NSOrderedSame;
1167
/* other string is 8 bit */
1169
if (a == 1) { /* exact string class, do not call method */
1170
a = (((NSShortInline8BitString *)aString)->cLength == 255)
1172
: ((NSShortInline8BitString *)aString)->cLength;
1173
if (a != range.length)
1174
/* strings differ in length */
1177
else if ((a = [aString cStringLength]) != range.length)
1178
/* strings differ in length */
1183
mbytes = self->cString;
1184
abytes = [(id)aString __compact8BitBytes];
1186
/* using memcmp is probably faster than looping on our own */
1187
return memcmp(self->cString, abytes, a) == 0 ? YES : NO;
1191
@end /* NSShortInline8BitString */
1193
@implementation NSCharacter8BitString /* final */
1202
- (id)initWithCString:(const char*)byteString length:(unsigned int)_length
1205
[[[InvalidUseOfMethodException alloc] initWithFormat:
1206
@"%@ can only handle a singe char", [self class]] raise];
1208
self->c[0] = byteString[0];
1213
- (id)initWithCharacters:(const unichar *)chars length:(unsigned int)_length
1216
[[[InvalidUseOfMethodException alloc] initWithFormat:
1217
@"%@ can only handle a singe char", [self class]] raise];
1219
self->c[0] = (char)chars[0];
1225
- (const char *)cString
1227
return &(self->c[0]);
1230
- (unsigned int)cStringLength
1235
- (unsigned int)length
1240
- (unichar)characterAtIndex:(unsigned int)index
1243
[[[IndexOutOfRangeException alloc]
1244
initWithFormat:@"index %d out of range in string %x of length 1",
1245
index, self] raise];
1251
- (NSString *)substringWithRange:(NSRange)aRange
1253
if (aRange.location == 0 && aRange.length == 1)
1255
if (aRange.length == 0)
1258
[[[IndexOutOfRangeException alloc]
1259
initWithFormat:@"range (%d,%d) in string %x of length 1",
1260
aRange.location, aRange.length, self] raise];
1264
- (char *)__compact8BitBytes
1266
return &(self->c[0]);
1271
register unsigned hash = 0, hash2;
1274
// UNICODE - must use a for independent of composed characters
1276
if ((hash2 = hash & 0xf0000000))
1277
hash ^= (hash2 >> 24) ^ hash2;
1282
@end /* NSCharacter8BitString */
1286
* String containing non-owned, zero termintated c-string
1289
@implementation NSNonOwned8BitString
1293
if (self->cLength || self->cString) {
1294
[[[InvalidUseOfMethodException alloc] initWithFormat:
1295
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1303
- (id)initWithCString:(char *)byteString
1304
length:(unsigned int)length copy:(BOOL)flag
1306
if (self->cLength || self->cString) {
1307
[[[InvalidUseOfMethodException alloc] initWithFormat:
1308
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1312
[[[InvalidUseOfMethodException alloc] initWithFormat:
1313
@"cannot send %s with flag set to YES to %@ to instance",
1314
sel_get_name(_cmd), NSStringFromClass([self class])] raise];
1317
cString = byteString;
1321
#if COLLECT_STRING_CLUSTER_STATISTICS
1324
NSNonOwned8BitString_dealloc_count++;
1325
NSNonOwned8BitString_total_len += self->cLength;
1330
- (const char *)cString
1332
return self->cString;
1335
- (unsigned int)cStringLength
1337
return self->cLength;
1340
- (unsigned int)length
1342
return self->cLength;
1345
- (unichar)characterAtIndex:(unsigned int)index
1347
if ((int)self->cLength == -1 || (index >= (unsigned)self->cLength)) {
1348
[[[IndexOutOfRangeException alloc]
1349
initWithFormat:@"index %d out of range in string %x of length %d",
1350
index, self, cLength] raise];
1353
return self->cString[index];
1356
- (NSString *)substringWithRange:(NSRange)aRange
1358
if (aRange.location + aRange.length > cLength) {
1359
[[[IndexOutOfRangeException alloc]
1360
initWithFormat:@"range (%d,%d) in string %x of length %d",
1361
aRange.location, aRange.length, self, cLength] raise];
1364
if (aRange.length == 0)
1367
return AUTORELEASE([[NSRange8BitString alloc]
1369
bytes:cString + aRange.location
1370
length:aRange.length]);
1373
- (char*)__compact8BitBytes
1375
return self->cString;
1378
@end /* NSNonOwned8BitString */
1380
@implementation NSOwned8BitString
1384
if (self->cLength || self->cString) {
1385
[[[InvalidUseOfMethodException alloc] initWithFormat:
1386
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1391
self->cString = NSZoneMallocAtomic([self zone], sizeof(char));
1392
self->cString[0] = 0;
1396
- (id)initWithCString:(char*)byteString
1397
length:(unsigned int)length
1400
if (self->cLength != 0 || self->cString != NULL) {
1401
[[[InvalidUseOfMethodException alloc] initWithFormat:
1402
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1406
self->cLength = length;
1408
self->cString = NSZoneMallocAtomic([self zone], sizeof(char)*(length+1));
1409
memcpy(self->cString, byteString, length);
1410
self->cString[self->cLength] = 0;
1413
self->cString = byteString;
1419
#if COLLECT_STRING_CLUSTER_STATISTICS
1420
NSOwned8BitString_dealloc_count++;
1421
NSOwned8BitString_total_len += self->cLength;
1423
lfFree(self->cString);
1427
@end /* NSOwned8BitString */
1430
@implementation NXConstantString
1432
- (oneway void)release
1441
- (unsigned)retainCount
1453
[self shouldNotImplement:_cmd];
1456
@end /* NXConstantString */
1458
@interface DummyNXConstantString : NSNonOwned8BitString
1461
@implementation DummyNXConstantString
1462
- (oneway void)release
1471
- (unsigned)retainCount
1483
[self shouldNotImplement:_cmd];
1488
static BOOL didLoad = NO;
1492
Class constantStringClass;
1493
Class constantStringMetaClass;
1497
metaClass = ((DummyNXConstantString*)self)->isa;
1498
constantStringClass = objc_lookup_class ("NXConstantString");
1499
constantStringMetaClass = constantStringClass->class_pointer;
1501
memcpy(constantStringClass, self, sizeof (struct objc_class));
1502
memcpy(constantStringMetaClass, metaClass, sizeof (struct objc_class));
1504
constantStringClass->name
1505
= constantStringMetaClass->name
1506
= "NXConstantString";
1508
class_add_behavior(constantStringClass, self);
1512
@end /* DummyNXConstantString */
1515
@implementation NSNonOwnedOpen8BitString
1517
#if COLLECT_STRING_CLUSTER_STATISTICS
1520
NSNonOwnedOpen8BitString_dealloc_count++;
1521
NSNonOwnedOpen8BitString_total_len += self->cLength;
1526
- (const char*)cString
1530
str = NSZoneMallocAtomic([self zone], sizeof(char)*(self->cLength + 1));
1531
memcpy(str, self->cString, self->cLength);
1533
#if !LIB_FOUNDATION_BOEHM_GC
1534
[NSAutoreleasedPointer autoreleasePointer:str];
1539
@end /* NSNonOwnedOpen8BitString */
1541
@implementation NSOwnedOpen8BitString /* final */
1543
#if COLLECT_STRING_CLUSTER_STATISTICS
1546
NSOwnedOpen8BitString_dealloc_count++;
1547
NSOwnedOpen8BitString_total_len += self->cLength;
1552
- (id)initWithCString:(char *)byteString
1553
length:(unsigned int)length copy:(BOOL)flag
1555
if (self->cLength || self->cString) {
1556
[[[InvalidUseOfMethodException alloc] initWithFormat:
1557
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1560
if (length != 0 && byteString == NULL) {
1561
[[[InvalidUseOfMethodException alloc] initWithFormat:
1562
@"passed NULL cstring to %s with a non-null length (%i)!",
1563
sel_get_name(_cmd), length]
1567
if (strlen(byteString) < length) {
1568
printf("LENGTH DIFFERS: %i vs %i\n", strlen(byteString), length);
1572
self->cLength = length;
1574
/* TODO: this is not tracked in dealloc? */
1576
NSZoneMallocAtomic([self zone], sizeof(char)*(length + 1));
1577
memcpy(cString, byteString, length);
1578
cString[length] = 0;
1581
self->cString = byteString;
1585
- (const char *)cString
1587
unsigned char *str = MallocAtomic(sizeof(char)*(self->cLength + 1));
1589
memcpy(str, self->cString, self->cLength);
1590
str[self->cLength] = 0;
1591
#if !LIB_FOUNDATION_BOEHM_GC
1592
[NSAutoreleasedPointer autoreleasePointer:str];
1597
@end /* NSOwnedOpen8BitString */
1599
@implementation NSRange8BitString /* final */
1601
- (id)initWithString:(NSString *)aParent
1602
bytes:(char *)bytes length:(unsigned int)length
1604
if (self->cLength != 0 || self->cString != NULL) {
1605
[[[InvalidUseOfMethodException alloc] initWithFormat:
1606
@"cannot send %s to non-mutable instance", sel_get_name(_cmd)]
1610
self->cString = bytes;
1611
self->cLength = length;
1612
self->parent = RETAIN(aParent);
1618
#if COLLECT_STRING_CLUSTER_STATISTICS
1619
NSRange8BitString_dealloc_count++;
1620
NSRange8BitString_total_len += self->cLength;
1622
RELEASE(self->parent);
1626
- (NSString *)substringWithRange:(NSRange)aRange
1628
if (aRange.location + aRange.length > cLength) {
1629
[[[IndexOutOfRangeException alloc]
1630
initWithFormat:@"range (%d,%d) in string %x of length %d",
1631
aRange.location, aRange.length, self, cLength] raise];
1634
if (aRange.length == 0)
1637
return AUTORELEASE([[NSRange8BitString alloc]
1638
initWithString:parent
1639
bytes:cString+aRange.location
1640
length:aRange.length]);
1645
register unsigned char *bytes;
1646
register unsigned hash = 0, hash2;
1649
bytes = self->cString;
1652
for (i = 0; i < n; i++) {
1654
// UNICODE - must use a for independent of composed characters
1656
if ((hash2 = hash & 0xf0000000))
1657
hash ^= (hash2 >> 24) ^ hash2;
1663
@end /* NSRange8BitString */