mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Store tiny strings (up to 8 ASCII characters) inside the pointer. Strings of
this length are fairly common, and this makes them very cheap to store / copy / compare (pointer comparisons test for equality). 8 characters seems to be enough for quite a lot of common uses, such as path components and tokens. There are possibly still some things constructing tiny strings and not using these. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@34181 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
93528274f9
commit
d728c938b2
1 changed files with 128 additions and 0 deletions
|
@ -693,6 +693,103 @@ static void GSStrWiden(GSStr s);
|
|||
static void getCString_u(GSStr self, char *buffer, unsigned int maxLength,
|
||||
NSRange aRange, NSRange *leftoverRange);
|
||||
|
||||
#if defined(OBJC_SMALL_OBJECT_SHIFT) && (OBJC_SMALL_OBJECT_SHIFT == 3)
|
||||
#define TINY_STRING_MASK 4
|
||||
BOOL useTinyStrings;
|
||||
/**
|
||||
* A GSTinyString is used on 64-bit platforms to store up to 8 ASCII (7-bit)
|
||||
* characters inside a pointer. Note that a mutable version of this class is
|
||||
* not possible, because modifying the string changes the pointer value.
|
||||
* The layout of a tiny string is as follows:
|
||||
struct
|
||||
{
|
||||
uintptr_t char0 :7;
|
||||
uintptr_t char1 :7;
|
||||
uintptr_t char2 :7;
|
||||
uintptr_t char3 :7;
|
||||
uintptr_t char4 :7;
|
||||
uintptr_t char5 :7;
|
||||
uintptr_t char6 :7;
|
||||
uintptr_t char7 :7;
|
||||
uintptr_t length :5;
|
||||
uintptr_t tag :3;
|
||||
};
|
||||
*/
|
||||
#define TINY_STRING_CHAR(s, x) ((s & (0xFE00000000000000 >> (x*7))) >> (57-(x*7)))
|
||||
#define TINY_STRING_LENGTH_MASK 0x1f
|
||||
#define TINY_STRING_LENGTH_SHIFT OBJC_SMALL_OBJECT_SHIFT
|
||||
@interface GSTinyString : NSString @end
|
||||
@implementation GSTinyString
|
||||
- (NSUInteger)length
|
||||
{
|
||||
uintptr_t s = (uintptr_t)self;
|
||||
return (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
||||
}
|
||||
- (unichar)characterAtIndex: (NSUInteger)anIndex
|
||||
{
|
||||
uintptr_t s = (uintptr_t)self;
|
||||
NSUInteger length = (s >> TINY_STRING_LENGTH_SHIFT) & TINY_STRING_LENGTH_MASK;
|
||||
if (anIndex >= length)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"-characterAtIndex: index out of range"];
|
||||
}
|
||||
// Implicit NULL terminator on slightly-too-long strings.
|
||||
if (anIndex == 8)
|
||||
{
|
||||
return '\0';
|
||||
}
|
||||
return TINY_STRING_CHAR(s, anIndex);
|
||||
}
|
||||
+ (void)load
|
||||
{
|
||||
useTinyStrings = objc_registerSmallObjectClass_np(self, TINY_STRING_MASK);
|
||||
}
|
||||
+ (id)alloc
|
||||
{
|
||||
return (id)TINY_STRING_MASK;
|
||||
}
|
||||
+ (id)allocWithZone: (NSZone*)aZone
|
||||
{
|
||||
return (id)TINY_STRING_MASK;
|
||||
}
|
||||
- (id)copy
|
||||
{
|
||||
return self;
|
||||
}
|
||||
- (id)copyWithZone: (NSZone*)aZone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
- (id)retain { return self; }
|
||||
- (id)autorelease { return self; }
|
||||
- (oneway void)release { }
|
||||
@end
|
||||
/**
|
||||
* Constructs a tiny string.
|
||||
*/
|
||||
static id createTinyString(const char *str, int length)
|
||||
{
|
||||
// No tiny string support detected at run time, give up
|
||||
if (!useTinyStrings) { return nil; }
|
||||
// String too long to fit in a pointer, give up
|
||||
if (length > 9) { return nil; }
|
||||
// String would fit if the last byte was an implicit 0, but it isn't.
|
||||
if ((length == 9) && str[8] != '\0') { return nil; }
|
||||
uintptr_t s = TINY_STRING_MASK;
|
||||
s |= length << TINY_STRING_LENGTH_SHIFT;
|
||||
for (unsigned int i = 0 ; i<length ; i++)
|
||||
{
|
||||
s |= ((uintptr_t)str[i]) << (57 - (i*7));
|
||||
}
|
||||
return (id)s;
|
||||
}
|
||||
#else
|
||||
static id createTinyString(const char *str, int length)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* The GSPlaceholderString class is used by the abstract cluster root
|
||||
* class to provide temporary objects that will be replaced as soon
|
||||
|
@ -848,6 +945,37 @@ fixBOM(unsigned char **bytes, NSUInteger*length, BOOL *owned,
|
|||
{
|
||||
const void *original = bytes;
|
||||
|
||||
if (useTinyStrings)
|
||||
{
|
||||
if (NSASCIIStringEncoding == encoding)
|
||||
{
|
||||
id tinyString = createTinyString(bytes, length);
|
||||
if (tinyString)
|
||||
{
|
||||
return tinyString;
|
||||
}
|
||||
}
|
||||
if (NSUTF8StringEncoding == encoding && (length < 9))
|
||||
{
|
||||
NSUInteger i;
|
||||
for (i=0 ; i<length ; i++)
|
||||
{
|
||||
if (((const char*)bytes)[i] & 0x80)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == length)
|
||||
{
|
||||
id tinyString = createTinyString(bytes, length);
|
||||
if (tinyString)
|
||||
{
|
||||
return tinyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixBOM((unsigned char**)&bytes, &length, &flag, encoding);
|
||||
/*
|
||||
* We need to copy the data if there is any, unless fixBOM()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue