diff --git a/CHANGES.txt b/CHANGES.txt index 3b0453521afb569dd59fb94d93d304690876b25c_Q0hBTkdFUy50eHQ=..eb69b441a80b4cd2a2771215fc68dde7a54db37e_Q0hBTkdFUy50eHQ= 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 2.1.3 released XXXX-XX-XX + +* Support the sort_keys option in C encoding speedups + http://code.google.com/p/simplejson/issues/detail?id=86 + Version 2.1.2 released 2010-11-01 * Correct wrong end when object_pairs_hook is used diff --git a/simplejson/_speedups.c b/simplejson/_speedups.c index 3b0453521afb569dd59fb94d93d304690876b25c_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw==..eb69b441a80b4cd2a2771215fc68dde7a54db37e_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw== 100644 --- a/simplejson/_speedups.c +++ b/simplejson/_speedups.c @@ -2185,6 +2185,5 @@ static PyObject *iteritems = NULL; PyObject *kstr = NULL; PyObject *ident = NULL; - PyObject *key, *value; PyObject *iter = NULL; PyObject *item = NULL; @@ -2189,5 +2188,6 @@ PyObject *iter = NULL; PyObject *item = NULL; + PyObject *items = NULL; PyObject *encoded = NULL; int skipkeys; Py_ssize_t idx; @@ -2232,7 +2232,45 @@ */ } - /* TODO: C speedup not implemented for sort_keys */ + if (PyObject_IsTrue(s->sort_keys)) { + /* First sort the keys then replace them with (key, value) tuples. */ + Py_ssize_t i, nitems; + if (PyDict_CheckExact(dct)) + items = PyDict_Keys(dct); + else + items = PyMapping_Keys(dct); + if (items == NULL) + goto bail; + if (!PyList_Check(items)) { + PyErr_SetString(PyExc_ValueError, "keys must return list"); + goto bail; + } + if (PyList_Sort(items) < 0) + goto bail; + nitems = PyList_GET_SIZE(items); + for (i = 0; i < nitems; i++) { + PyObject *key, *value; + key = PyList_GET_ITEM(items, i); + value = PyDict_GetItem(dct, key); + item = PyTuple_Pack(2, key, value); + if (item == NULL) + goto bail; + PyList_SET_ITEM(items, i, item); + Py_DECREF(key); + } + } + else { + if (PyDict_CheckExact(dct)) + items = PyDict_Items(dct); + else + items = PyMapping_Items(dct); + } + if (items == NULL) + goto bail; + iter = PyObject_GetIter(items); + Py_DECREF(items); + if (iter == NULL) + goto bail; skipkeys = PyObject_IsTrue(s->skipkeys); idx = 0; @@ -2236,7 +2274,4 @@ skipkeys = PyObject_IsTrue(s->skipkeys); idx = 0; - iter = PyObject_CallMethodObjArgs(dct, iteritems, NULL); - if (iter == NULL) - goto bail; while ((item = PyIter_Next(iter))) { @@ -2242,5 +2277,9 @@ while ((item = PyIter_Next(iter))) { - - key = PyTuple_GetItem(item, 0); + PyObject *encoded, *key, *value; + if (!PyTuple_Check(item) || Py_SIZE(item) != 2) { + PyErr_SetString(PyExc_ValueError, "items must return 2-tuples"); + goto bail; + } + key = PyTuple_GET_ITEM(item, 0); if (key == NULL) goto bail; @@ -2245,5 +2284,5 @@ if (key == NULL) goto bail; - value = PyTuple_GetItem(item, 1); + value = PyTuple_GET_ITEM(item, 1); if (value == NULL) goto bail; @@ -2248,6 +2287,6 @@ if (value == NULL) goto bail; - + encoded = PyDict_GetItem(s->key_memo, key); if (encoded != NULL) { Py_INCREF(encoded); @@ -2261,8 +2300,10 @@ if (kstr == NULL) goto bail; } - else if (PyInt_Check(key) || PyLong_Check(key)) { - kstr = PyObject_Str(key); + else if (key == Py_True || key == Py_False || key == Py_None) { + /* This must come before the PyInt_Check because + True and False are also 1 and 0.*/ + kstr = _encoded_const(key); if (kstr == NULL) goto bail; } @@ -2266,8 +2307,8 @@ if (kstr == NULL) goto bail; } - else if (key == Py_True || key == Py_False || key == Py_None) { - kstr = _encoded_const(key); + else if (PyInt_Check(key) || PyLong_Check(key)) { + kstr = PyObject_Str(key); if (kstr == NULL) goto bail; } @@ -2326,7 +2367,7 @@ bail: Py_XDECREF(encoded); - Py_XDECREF(item); + Py_XDECREF(items); Py_XDECREF(iter); Py_XDECREF(kstr); Py_XDECREF(ident); diff --git a/simplejson/encoder.py b/simplejson/encoder.py index 3b0453521afb569dd59fb94d93d304690876b25c_c2ltcGxlanNvbi9lbmNvZGVyLnB5..eb69b441a80b4cd2a2771215fc68dde7a54db37e_c2ltcGxlanNvbi9lbmNvZGVyLnB5 100644 --- a/simplejson/encoder.py +++ b/simplejson/encoder.py @@ -268,7 +268,7 @@ key_memo = {} if (_one_shot and c_make_encoder is not None - and self.indent is None and not self.sort_keys): + and self.indent is None): _iterencode = c_make_encoder( markers, self.default, _encoder, self.indent, self.key_separator, self.item_separator, self.sort_keys, diff --git a/simplejson/tests/test_encode_basestring_ascii.py b/simplejson/tests/test_encode_basestring_ascii.py index 3b0453521afb569dd59fb94d93d304690876b25c_c2ltcGxlanNvbi90ZXN0cy90ZXN0X2VuY29kZV9iYXNlc3RyaW5nX2FzY2lpLnB5..eb69b441a80b4cd2a2771215fc68dde7a54db37e_c2ltcGxlanNvbi90ZXN0cy90ZXN0X2VuY29kZV9iYXNlc3RyaW5nX2FzY2lpLnB5 100644 --- a/simplejson/tests/test_encode_basestring_ascii.py +++ b/simplejson/tests/test_encode_basestring_ascii.py @@ -39,3 +39,8 @@ # result, expect, fname, input_string)) self.assertEquals(result, expect, '%r != %r for %s(%r)' % (result, expect, fname, input_string)) + + def test_sorted_dict(self): + items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] + s = simplejson.dumps(dict(items), sort_keys=True) + self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}')