1
0
Fork 0
mirror of https://github.com/ultrajson/ultrajson.git synced 2024-06-11 06:56:11 +02:00

- Optimization in progress

- Added __fastcall which currently breaks gcc builds, to be fixed soon
This commit is contained in:
Jonas Tärnström 2011-03-01 22:24:06 +01:00
parent 60f0258389
commit c5966a244e
7 changed files with 203 additions and 143 deletions

View File

@ -116,6 +116,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="C:\Python26\include;../"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@ import json
import cjson
import time
user = { "userId": 3381293, "username": "johndoe", "fullname": u"John Doe the Second", "isAuthorized": True, "approval": 31.1471, "jobs": [ 1, 2 ], "currJob": None }
user = { "userId": 3381293, "age": 213, "username": "johndoe", "fullname": u"John Doe the Second", "isAuthorized": True, "liked": 31231.31231202, "approval": 31.1471, "jobs": [ 1, 2 ], "currJob": None }
friends = [ user, user, user, user, user, user, user, user ]
testObject = [ [user, friends], [user, friends], [user, friends], [user, friends], [user, friends], [user, friends]]
@ -37,7 +37,7 @@ def jsonDec():
x = json.loads(decodeData)
def cjsonDec():
x = cjson.encode(decodeData)
x = cjson.decode(decodeData)
"""=========================================================================="""
@ -45,7 +45,7 @@ def cjsonDec():
if __name__ == "__main__":
import timeit
COUNT = 10000
COUNT = 3000
"""
print "ujson encode : %.05f calls/sec" % (COUNT / min(timeit.repeat("ujsonEnc()", "from __main__ import ujsonEnc", time.clock,5, COUNT)), )
print "simplejson encode : %.05f calls/sec" % (COUNT / min(timeit.repeat("simplejsonEnc()", "from __main__ import simplejsonEnc", time.clock,5, COUNT)), )
@ -58,9 +58,9 @@ if __name__ == "__main__":
file.write(decodeData)
file.close()
print "cjson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("cjsonDec()", "from __main__ import cjsonDec", time.clock,5, COUNT)), )
print "ujson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("ujsonDec()", "from __main__ import ujsonDec", time.clock,5, COUNT)), )
print "simplejson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("simplejsonDec()", "from __main__ import simplejsonDec", time.clock,5, COUNT)), )
print "ujson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("ujsonDec()", "from __main__ import ujsonDec", time.clock,10, COUNT)), )
print "cjson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("cjsonDec()", "from __main__ import cjsonDec", time.clock,10, COUNT)), )
print "simplejson decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("simplejsonDec()", "from __main__ import simplejsonDec", time.clock,10, COUNT)), )
#print "json decode : %.05f calls/sec" % (COUNT / min(timeit.repeat("jsonDec()", "from __main__ import jsonDec", time.clock, 5, COUNT)), )

Binary file not shown.

View File

@ -24,8 +24,14 @@ class UltraJSONTests(TestCase):
pass
def test_encodeStringConversion(self):
input = "A \"string\"\"\\\/\b\f\n\r\t"
input = "A string \\ \/ \b \f \n \r \t"
output = ujson.encode(input)
print "OUTPUT ===========", output
print "CJSON SAYS ========", json.loads(output)
print "UJSON SAYS =======", ujson.decode(output)
self.assertEquals(input, json.loads(output))
self.assertEquals(output, json.dumps(input))
self.assertEquals(input, ujson.decode(output))

View File

@ -126,8 +126,11 @@ Encoding in details:
#endif
#ifdef _WIN32
typedef __int64 JSLONG;
typedef unsigned __int64 JSULONG;
#define EXPORTFUNCTION __declspec(dllexport)
#define INLINEFUNCTION __inline
typedef unsigned __int32 uint32_t;

View File

@ -50,7 +50,7 @@ struct DecoderState
JSONObjectDecoder *dec;
};
JSOBJ decode_any( struct DecoderState *ds);
JSOBJ __fastcall decode_any( struct DecoderState *ds);
typedef JSOBJ (*PFN_DECODER)( struct DecoderState *ds);
PFN_DECODER g_identTable[256] = { NULL };
@ -70,7 +70,7 @@ static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000
#define RETURN_JSOBJ_NULLCHECK(_expr) return(_expr);
INLINEFUNCTION double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
{
return (intValue + (frcValue / g_pow10[frcDecimalCount])) * intNeg;
}
@ -83,22 +83,15 @@ JSOBJ SetError( struct DecoderState *ds, int offset, const char *message)
}
JSOBJ decode_numeric ( struct DecoderState *ds)
JSOBJ __fastcall decode_numeric ( struct DecoderState *ds)
{
int intNeg = 1;
int expNeg = 1;
int expNeg;
int chr;
int decimalCount = 0;
JSLONG intValue;
double frcValue = 0.0;
double expValue;
//return ds->dec->newInteger(31337);
ds->lastType = JT_INVALID;
// Go one back since the scanner ate one
ds->start --;
if (*(ds->start) == '-')
{
@ -126,6 +119,7 @@ JSOBJ decode_numeric ( struct DecoderState *ds)
case '8':
case '9':
//FIXME: Check for arithemtic overflow here
//PERF: Don't do 64-bit arithmetic here unless we know we have to
intValue = intValue * 10 + (JSLONG) (chr - 48);
ds->start ++;
break;
@ -210,6 +204,8 @@ BREAK_FRC_LOOP:
RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue, frcValue, decimalCount)));
DECODE_EXPONENT:
expNeg = 1;
if (*(ds->start) == '-')
{
expNeg = -1;
@ -262,9 +258,9 @@ BREAK_EXP_LOOP:
RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue , frcValue, decimalCount) * pow(10.0, expValue)));
}
JSOBJ decode_true ( struct DecoderState *ds)
JSOBJ __fastcall decode_true ( struct DecoderState *ds)
{
ds->lastType = JT_INVALID;
ds->start ++;
if (*(ds->start++) != 'r')
goto SETERROR;
@ -280,9 +276,9 @@ SETERROR:
return SetError(ds, -1, "Unexpected character found when decoding 'true'");
}
JSOBJ decode_false ( struct DecoderState *ds)
JSOBJ __fastcall decode_false ( struct DecoderState *ds)
{
ds->lastType = JT_INVALID;
ds->start ++;
if (*(ds->start++) != 'a')
goto SETERROR;
@ -302,9 +298,9 @@ SETERROR:
}
JSOBJ decode_null ( struct DecoderState *ds)
JSOBJ __fastcall decode_null ( struct DecoderState *ds)
{
ds->lastType = JT_INVALID;
ds->start ++;
if (*(ds->start++) != 'u')
goto SETERROR;
@ -341,12 +337,44 @@ static char g_unescapeLookup[] = {
/* 0xf0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
};
JSOBJ decode_string ( struct DecoderState *ds)
__inline void __fastcall SkipWhitespace(struct DecoderState *ds)
{
while (1)
{
switch (*ds->start)
{
case ' ':
case '\t':
case '\r':
case '\n':
ds->start ++;
break;
/*
case '\x00':
case '\x01':
case '\x02':
case '\x03':
case '\x04':
case '\x05':
case '\x06':
case '\x07':
return;
*/
default:
return;
}
}
}
JSOBJ __fastcall decode_string ( struct DecoderState *ds)
{
char *escOffset;
char chr;
size_t escLen = (ds->escEnd - ds->escStart);
ds->lastType = JT_INVALID;
ds->start ++;
if ( (ds->end - ds->start) > escLen)
{
@ -369,50 +397,63 @@ JSOBJ decode_string ( struct DecoderState *ds)
escOffset = ds->escStart;
while (1)
while(1)
{
chr = (*ds->start++);
switch (chr)
{
case '\0':
return SetError(ds, -1, "Unmatched ''\"' when when decoding 'string'");
case '\0':
return SetError(ds, -1, "Unmatched ''\"' when when decoding 'string'");
case '\"':
ds->lastType = JT_UTF8;
RETURN_JSOBJ_NULLCHECK(ds->dec->newString(ds->escStart, escOffset));
case '\"':
ds->lastType = JT_UTF8;
RETURN_JSOBJ_NULLCHECK(ds->dec->newString(ds->escStart, escOffset));
case '\\':
if (*ds->start == '\0')
{
return SetError(ds, -1, "Unterminated escape sequence when decoding 'string'");
}
case '\\':
switch (*(ds->start))
{
case '\\': *(escOffset++) = '\\'; ds->start++; continue;
case '\"': *(escOffset++) = '\"'; ds->start++; continue;
case '/': *(escOffset++) = '/'; ds->start++; continue;
case 'b': *(escOffset++) = '\b'; ds->start++; continue;
case 'f': *(escOffset++) = '\f'; ds->start++; continue;
case 'n': *(escOffset++) = '\n'; ds->start++; continue;
case 'r': *(escOffset++) = '\r'; ds->start++; continue;
case 't': *(escOffset++) = '\t'; ds->start++; continue;
chr = g_unescapeLookup[ (unsigned char) (*ds->start++)];
case '\0':
return SetError(ds, -1, "Unterminated escape sequence when decoding 'string'");
if (chr == '\0')
{
return SetError(ds, -1, "Unrecognized escape sequence when decoding 'string'");
}
break;
default:
return SetError(ds, -1, "Unrecognized escape sequence when decoding 'string'");
}
break;
default:
*(escOffset++) = chr;
}
*(escOffset++) = chr;
}
}
JSOBJ decode_array( struct DecoderState *ds)
JSOBJ __fastcall decode_array( struct DecoderState *ds)
{
JSOBJ itemValue;
JSOBJ newObj = ds->dec->newArray();
ds->lastType = JT_INVALID;
ds->start ++;
while ((*ds->start) != '\0')
while (1)//(*ds->start) != '\0')
{
SkipWhitespace(ds);
if ((*ds->start) == ']')
{
return newObj;
}
itemValue = decode_any(ds);
if (itemValue == NULL)
@ -422,142 +463,139 @@ JSOBJ decode_array( struct DecoderState *ds)
}
ds->dec->arrayAddItem (newObj, itemValue);
SkipWhitespace(ds);
switch (*(ds->start++))
{
case ']':
return newObj;
case ',':
break;
default:
return SetError(ds, -1, "Unexpected character in found when decoding array value");
}
}
//FIXME: Must release newObj here!
return SetError(ds, -1, "Unmatched ']' when decoding 'array'");
}
JSOBJ decode_object( struct DecoderState *ds)
JSOBJ __fastcall decode_object( struct DecoderState *ds)
{
JSOBJ itemName;
JSOBJ itemValue;
JSOBJ newObj = ds->dec->newObject();
ds->lastType = JT_INVALID;
while ((*ds->start) != '\0')
ds->start ++;
while (1)
{
SkipWhitespace(ds);
if ((*ds->start) == '}')
{
return newObj;
}
ds->lastType = JT_INVALID;
itemName = decode_any(ds);
//FIXME: Why should we accept this?
if (itemName == NULL)
{
ds->lastType = JT_OBJECT;
return newObj;
}
if (itemName)
if (ds->lastType != JT_UTF8)
{
if (ds->lastType != JT_UTF8)
{
return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
}
return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
}
// Expect ':'
while ((*ds->start) != '\0')
{
if (*(ds->start++) == ':')
break;
}
SkipWhitespace(ds);
if (ds->start == ds->end)
{
return SetError(ds, -1, "No ':' found when decoding object value");
}
if (*(ds->start++) != ':')
{
return SetError(ds, -1, "No ':' found when decoding object value");
}
itemValue = decode_any(ds);
ds->dec->objectAddKey (newObj, itemName, itemValue);
SkipWhitespace(ds);
itemValue = decode_any(ds);
//FIXME: itemName will leak here
if (itemValue == NULL)
{
return newObj;
}
ds->dec->objectAddKey (newObj, itemName, itemValue);
SkipWhitespace(ds);
switch (*(ds->start++))
{
case '}':
return newObj;
case ',':
break;
default:
return SetError(ds, -1, "Unexpected character in found when decoding object value");
}
}
//FIXME: newobj will leak here
return SetError(ds, -1, "Unmatched '}' when decoding object");
}
JSOBJ decode_array_begin( struct DecoderState *ds)
JSOBJ __fastcall decode_any(struct DecoderState *ds)
{
return decode_array(ds);
}
JSOBJ decode_array_end( struct DecoderState *ds)
{
return NULL;
}
JSOBJ decode_object_begin( struct DecoderState *ds)
{
return decode_object(ds);
}
JSOBJ decode_object_end( struct DecoderState *ds)
{
return NULL;
}
JSOBJ decode_item_separator( struct DecoderState *ds)
{
//FIXME: Validate that we are inside array or object here
return decode_any(ds);
}
JSOBJ decode_any(struct DecoderState *ds)
{
ds->lastType = JT_INVALID;
while (1)
{
switch ((*ds->start++))
switch (*ds->start)
{
case '\"': return decode_string (ds);
case '0': return decode_numeric (ds);
case '1': return decode_numeric (ds);
case '2': return decode_numeric (ds);
case '3': return decode_numeric (ds);
case '4': return decode_numeric (ds);
case '5': return decode_numeric (ds);
case '6': return decode_numeric (ds);
case '7': return decode_numeric (ds);
case '8': return decode_numeric (ds);
case '9': return decode_numeric (ds);
case '-': return decode_numeric (ds);
case '[': return decode_array (ds);
case '\"':
return decode_string (ds);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return decode_numeric (ds);
case '[': return decode_array (ds);
case '{': return decode_object (ds);
case 't': return decode_true (ds);
case 'f': return decode_false (ds);
case 'n': return decode_null (ds);
/*
case '}': return decode_object_end (ds);
case ']': return decode_array_end (ds);
case ',': return decode_item_separator (ds);
*/
case '}':
case ']':
return NULL;
case ',':
// FIXME: Validate
// Trailers
break;
case ' ':
case '\t':
case '\r':
case '\n':
// White space
ds->start ++;
break;
default:
return NULL;
return SetError(ds, -1, "Expected object or value");
}
}
return NULL;
}
@ -573,7 +611,6 @@ JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuf
ds.start = (char *) buffer;
ds.end = ds.start + cbBuffer;
ds.lastType = JT_INVALID;
ds.escStart = escBuffer;
ds.escEnd = ds.escStart + sizeof(escBuffer);
ds.escHeap = 0;
@ -584,6 +621,7 @@ JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuf
if (s_once)
{
//FIXME: Move to static initialization instead
/*
g_identTable['\"'] = decode_string;
g_identTable['0'] = decode_numeric;
g_identTable['1'] = decode_numeric;
@ -609,6 +647,7 @@ JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuf
{
g_identTable[index] = (PFN_DECODER) 1;
}
*/
for (index = 0; index < 256; index ++)
{