Added uniquing in serializer

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3272 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 1998-11-20 12:12:08 +00:00
parent e3eeee7d74
commit 14f870e4f6
3 changed files with 318 additions and 24 deletions

View file

@ -44,6 +44,27 @@
intoData: (NSMutableData*)d;
@end
#ifndef NO_GNUSTEP
/*
* GNUstep extends serialization by having the option to make the
* resulting data more compact by ensuring that repeated strings
* are only stored once. If the property-list has a lot of repeated
* strings in it, this will be both faster and more space efficient
* but it will be slower if the property-list has few repeated
* strings. The default is to generate compact versions of the data.
*
* The [+shouldBeCompact:] method sets default behavior.
* The [+serializePropertyList:intoData:compact:] method lets you
* override the default behavior.
*/
@interface NSSerializer (GNUstep)
+ (void) shouldBeCompact: (BOOL)flag;
+ (void) serializePropertyList: (id)propertyList
intoData: (NSMutableData*)d
compact: (BOOL)flag;
@end
#endif
@interface NSDeserializer: NSObject
+ (id) deserializePropertyListFromData: (NSData*)data
atCursor: (unsigned int*)cursor

147
Source/FastArray.x Normal file
View file

@ -0,0 +1,147 @@
/* A fast inline array table implementation without objc method overhead.
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Created: Nov 1998
*
* This file is part of the GNUstep Base Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
#include <Foundation/NSObject.h>
#include <Foundation/NSZone.h>
/* To easily un-inline functions for debugging */
#ifndef INLINE
#define INLINE inline
#endif
/*
* This file should be INCLUDED in files wanting to use the FastArray
* functions - these are all declared inline for maximum performance.
*
* The file including this one may predefine some macros to alter
* the behaviour (default macros assume the items are NSObjects
* that are to be retained in the array) ...
*
* FAST_ARRAY_RETAIN()
* Macro to retain an array item
*
* FAST_ARRAY_RELEASE()
* Macro to release the item.
*
*/
#ifndef FAST_ARRAY_RETAIN
#define FAST_ARRAY_RETAIN(X) [(X).o retain]
#endif
#ifndef FAST_ARRAY_RELEASE
#define FAST_ARRAY_RELEASE(X) [(X).o release]
#endif
typedef union {
id o;
Class c;
int i;
unsigned I;
long l;
unsigned long L;
void *p;
const void *P;
char *s;
const char *S;
} FastArrayItem;
struct _FastArray {
FastArrayItem *ptr;
unsigned count;
unsigned cap;
unsigned old;
NSZone *zone;
};
typedef struct _FastArray FastArray_t;
typedef struct _FastArray *FastArray;
static INLINE void
FastArrayAddItem(FastArray array, FastArrayItem item)
{
if (array->count == array->cap)
{
unsigned next;
FastArrayItem *tmp;
next = array->cap + array->old;
tmp = NSZoneRealloc(array->zone, array->ptr, next*sizeof(FastArrayItem));
if (tmp == 0)
{
[NSException raise: NSMallocException
format: @"failed to grow FastArray"];
}
array->ptr = tmp;
array->old = array->cap;
array->cap = next;
}
array->ptr[array->count++] = FAST_ARRAY_RETAIN(item);
}
static INLINE void
FastArrayRemoveItemAtIndex(FastArray array, unsigned index)
{
NSCAssert(index < array->count, NSInvalidArgumentException);
FAST_ARRAY_RELEASE(array->ptr[index]);
while (++index < array->count)
array->ptr[index-1] = array->ptr[index];
array->count--;
}
static INLINE FastArrayItem
FastArrayItemAtIndex(FastArray array, unsigned index)
{
return array->ptr[index];
}
static INLINE unsigned
FastArrayLength(FastArray array)
{
return array->count;
}
static INLINE void
FastArrayEmpty(FastArray array)
{
unsigned i = array->count;
while (i-- > 0)
FAST_ARRAY_RELEASE(array->ptr[i]);
NSZoneFree(array->zone, (void*)array->ptr);
}
static INLINE FastArray
FastArrayInitWithZoneAndCapacity(FastArray array, NSZone *zone, size_t capacity)
{
array->zone = zone;
array->count = 0;
if (capacity < 1)
capacity = 2;
array->cap = capacity;
array->old = capacity/2;
array->ptr=(FastArrayItem*)NSZoneMalloc(zone,capacity*sizeof(FastArrayItem));
return array;
}

View file

@ -40,17 +40,39 @@
@class NSGMutableDictionary;
@class NSDataMalloc;
/*
* Setup for inline operation of string map tables.
*/
#define FAST_MAP_RETAIN_KEY(X) X
#define FAST_MAP_RELEASE_KEY(X)
#define FAST_MAP_RETAIN_VAL(X) X
#define FAST_MAP_RELEASE_VAL(X)
#define FAST_MAP_HASH(X) [(X).o hash]
#define FAST_MAP_EQUAL(X,Y) [(X).o isEqualToString: (Y).o]
#include "FastMap.x"
/*
* Setup for inline operation of string arrays.
*/
#define FAST_ARRAY_RETAIN(X) X
#define FAST_ARRAY_RELEASE(X)
#include "FastArray.x"
/*
* Define constants for data types and variables to hold them.
*/
#define ST_CSTRING 0
#define ST_STRING 1
#define ST_ARRAY 2
#define ST_MARRAY 3
#define ST_DICT 4
#define ST_MDICT 5
#define ST_DATA 6
#define ST_XREF 0
#define ST_CSTRING 1
#define ST_STRING 2
#define ST_ARRAY 3
#define ST_MARRAY 4
#define ST_DICT 5
#define ST_MDICT 6
#define ST_DATA 7
static char st_xref = (char)ST_XREF;
static char st_cstring = (char)ST_CSTRING;
static char st_string = (char)ST_STRING;
static char st_array = (char)ST_ARRAY;
@ -77,6 +99,9 @@ typedef struct {
unsigned int (*lenImp)(); // Length of data.
void (*serImp)(); // Serialize integer.
void (*setImp)(); // Set length of data.
unsigned count; // String counter.
FastMapTable_t map; // For uniquing.
BOOL shouldUnique; // Do we do uniquing?
} _NSSerializerInfo;
static SEL appSel = @selector(appendBytes:length:);
@ -86,7 +111,7 @@ static SEL serSel = @selector(serializeInt:);
static SEL setSel = @selector(setLength:);
static void
initSerializerInfo(_NSSerializerInfo* info, NSMutableData *d)
initSerializerInfo(_NSSerializerInfo* info, NSMutableData *d, BOOL u)
{
Class c = fastClass(d);
@ -96,6 +121,20 @@ initSerializerInfo(_NSSerializerInfo* info, NSMutableData *d)
info->lenImp = (unsigned int (*)())get_imp(c, lenSel);
info->serImp = (void (*)())get_imp(c, serSel);
info->setImp = (void (*)())get_imp(c, setSel);
info->shouldUnique = u;
(*info->appImp)(d, appSel, &info->shouldUnique, 1);
if (u)
{
FastMapInitWithZoneAndCapacity(&info->map, NSDefaultMallocZone(), 16);
info->count = 0;
}
}
static void
endSerializerInfo(_NSSerializerInfo* info)
{
if (info->shouldUnique)
FastMapEmptyMap(&info->map);
}
static id
@ -106,25 +145,61 @@ serializeToInfo(id object, _NSSerializerInfo* info)
if (c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString ||
c == _fastCls._NXConstantString)
{
unsigned slen = [object cStringLength] + 1;
unsigned dlen;
FastMapNode node;
(*info->appImp)(info->data, appSel, &st_cstring, 1);
(*info->serImp)(info->data, serSel, slen);
dlen = (*info->lenImp)(info->data, lenSel);
(*info->setImp)(info->data, setSel, dlen + slen);
[object getCString: (*info->datImp)(info->data, datSel) + dlen];
if (info->shouldUnique)
node = FastMapNodeForKey(&info->map, (FastMapItem)object);
else
node = 0;
if (node == 0)
{
unsigned slen;
unsigned dlen;
slen = [object cStringLength] + 1;
(*info->appImp)(info->data, appSel, &st_cstring, 1);
(*info->serImp)(info->data, serSel, slen);
dlen = (*info->lenImp)(info->data, lenSel);
(*info->setImp)(info->data, setSel, dlen + slen);
[object getCString: (*info->datImp)(info->data, datSel) + dlen];
if (info->shouldUnique)
FastMapAddPair(&info->map,
(FastMapItem)object, (FastMapItem)info->count++);
}
else
{
(*info->appImp)(info->data, appSel, &st_xref, 1);
(*info->serImp)(info->data, serSel, node->value.I);
}
}
else if (fastClassIsKindOfClass(c, _fastCls._NSString))
{
unsigned slen = [object length];
unsigned dlen;
FastMapNode node;
(*info->appImp)(info->data, appSel, &st_string, 1);
(*info->serImp)(info->data, serSel, slen);
dlen = (*info->lenImp)(info->data, lenSel);
(*info->setImp)(info->data, setSel, dlen + slen*sizeof(unichar));
[object getCharacters: (*info->datImp)(info->data, datSel) + dlen];
if (info->shouldUnique)
node = FastMapNodeForKey(&info->map, (FastMapItem)object);
else
node = 0;
if (node == 0)
{
unsigned slen;
unsigned dlen;
slen = [object length];
(*info->appImp)(info->data, appSel, &st_string, 1);
(*info->serImp)(info->data, serSel, slen);
dlen = (*info->lenImp)(info->data, lenSel);
(*info->setImp)(info->data, setSel, dlen + slen*sizeof(unichar));
[object getCharacters: (*info->datImp)(info->data, datSel) + dlen];
if (info->shouldUnique)
FastMapAddPair(&info->map,
(FastMapItem)object, (FastMapItem)info->count++);
}
else
{
(*info->appImp)(info->data, appSel, &st_xref, 1);
(*info->serImp)(info->data, serSel, node->value.I);
}
}
else if (fastClassIsKindOfClass(c, ArrayClass))
{
@ -191,6 +266,8 @@ serializeToInfo(id object, _NSSerializerInfo* info)
@implementation NSSerializer
static BOOL shouldBeCompact = YES;
+ (void) initialize
{
if (self == [NSSerializer class])
@ -206,10 +283,13 @@ serializeToInfo(id object, _NSSerializerInfo* info)
+ (NSData*) serializePropertyList: (id)propertyList
{
_NSSerializerInfo info;
NSMutableData *d;
NSAssert(propertyList != nil, NSInvalidArgumentException);
initSerializerInfo(&info, [NSMutableData dataWithCapacity: 1024]);
d = [NSMutableData dataWithCapacity: 1024];
initSerializerInfo(&info, d, shouldBeCompact);
serializeToInfo(propertyList, &info);
endSerializerInfo(&info);
return info.data;
}
@ -220,8 +300,29 @@ serializeToInfo(id object, _NSSerializerInfo* info)
NSAssert(propertyList != nil, NSInvalidArgumentException);
NSAssert(d != nil, NSInvalidArgumentException);
initSerializerInfo(&info, d);
initSerializerInfo(&info, d, shouldBeCompact);
serializeToInfo(propertyList, &info);
endSerializerInfo(&info);
}
@end
@implementation NSSerializer (GNUstep)
+ (void) serializePropertyList: (id)propertyList
intoData: (NSMutableData*)d
compact: (BOOL)flag
{
_NSSerializerInfo info;
NSAssert(propertyList != nil, NSInvalidArgumentException);
NSAssert(d != nil, NSInvalidArgumentException);
initSerializerInfo(&info, d, flag);
serializeToInfo(propertyList, &info);
endSerializerInfo(&info);
}
+ (void) shouldBeCompact: (BOOL)flag
{
shouldBeCompact = flag;
}
@end
@ -240,8 +341,10 @@ typedef struct {
NSData *data;
unsigned *cursor;
BOOL mutable;
BOOL didUnique;
void (*debImp)();
unsigned int (*deiImp)();
FastArray_t array;
} _NSDeserializerInfo;
static SEL debSel = @selector(deserializeBytes:length:atCursor:);
@ -255,6 +358,16 @@ initDeserializerInfo(_NSDeserializerInfo* info, NSData *d, unsigned *c, BOOL m)
info->mutable = m;
info->debImp = (void (*)())[d methodForSelector: debSel];
info->deiImp = (unsigned int (*)())[d methodForSelector: deiSel];
(*info->debImp)(d, debSel, &info->didUnique, 1, c);
if (info->didUnique)
FastArrayInitWithZoneAndCapacity(&info->array, NSDefaultMallocZone(), 16);
}
static void
endDeserializerInfo(_NSDeserializerInfo* info)
{
if (info->didUnique)
FastArrayEmpty(&info->array);
}
static id
@ -268,6 +381,11 @@ deserializeFromInfo(_NSDeserializerInfo* info)
switch (code)
{
case ST_XREF:
{
return [FastArrayItemAtIndex(&info->array, size).o retain];
}
case ST_CSTRING:
{
NSGCString *s;
@ -278,6 +396,8 @@ deserializeFromInfo(_NSDeserializerInfo* info)
s = [s initWithCStringNoCopy: b
length: size-1
fromZone: NSDefaultMallocZone()];
if (info->didUnique)
FastArrayAddItem(&info->array, (FastArrayItem)s);
return s;
}
@ -291,6 +411,8 @@ deserializeFromInfo(_NSDeserializerInfo* info)
s = [s initWithCharactersNoCopy: b
length: size
fromZone: NSDefaultMallocZone()];
if (info->didUnique)
FastArrayAddItem(&info->array, (FastArrayItem)s);
return s;
}
@ -431,6 +553,7 @@ deserializeFromInfo(_NSDeserializerInfo* info)
- (void) dealloc
{
[info.data release];
endDeserializerInfo(&info);
[plist release];
[super dealloc];
}
@ -495,6 +618,7 @@ deserializeFromInfo(_NSDeserializerInfo* info)
NSAssert(cursor != 0, NSInvalidArgumentException);
initDeserializerInfo(&info, data, cursor, flag);
o = deserializeFromInfo(&info);
endDeserializerInfo(&info);
[o autorelease];
return o;
}
@ -509,6 +633,7 @@ deserializeFromInfo(_NSDeserializerInfo* info)
NSAssert(data != nil, NSInvalidArgumentException);
initDeserializerInfo(&info, data, &cursor, flag);
o = deserializeFromInfo(&info);
endDeserializerInfo(&info);
[o autorelease];
return o;
}
@ -527,6 +652,7 @@ deserializeFromInfo(_NSDeserializerInfo* info)
initDeserializerInfo(&info, data, cursor, flag);
o = deserializeFromInfo(&info);
endDeserializerInfo(&info);
[o autorelease];
return o;
}