Commit d07280ba authored by Stefan Behnel's avatar Stefan Behnel

Tune dict lookups with Unicode string keys.

parent d3830389
...@@ -3883,6 +3883,8 @@ class IndexNode(_IndexingBaseNode): ...@@ -3883,6 +3883,8 @@ class IndexNode(_IndexingBaseNode):
if not self.is_temp: if not self.is_temp:
# all handled in self.calculate_result_code() # all handled in self.calculate_result_code()
return return
utility_code = None
if self.type.is_pyobject: if self.type.is_pyobject:
error_value = 'NULL' error_value = 'NULL'
if self.index.type.is_int: if self.index.type.is_int:
...@@ -3892,32 +3894,39 @@ class IndexNode(_IndexingBaseNode): ...@@ -3892,32 +3894,39 @@ class IndexNode(_IndexingBaseNode):
function = "__Pyx_GetItemInt_Tuple" function = "__Pyx_GetItemInt_Tuple"
else: else:
function = "__Pyx_GetItemInt" function = "__Pyx_GetItemInt"
code.globalstate.use_utility_code( utility_code = TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c")
TempitaUtilityCode.load_cached("GetItemInt", "ObjectHandling.c"))
else: else:
if self.base.type is dict_type: if self.base.type is dict_type:
function = "__Pyx_PyDict_GetItem" if self.index.type in (str_type, unicode_type):
code.globalstate.use_utility_code( function = "__Pyx_PyDict_GetItemUnicode"
UtilityCode.load_cached("DictGetItem", "ObjectHandling.c")) utility_code = UtilityCode.load_cached("DictGetItemUnicode", "ObjectHandling.c")
else:
function = "__Pyx_PyDict_GetItem"
utility_code = UtilityCode.load_cached("DictGetItem", "ObjectHandling.c")
elif self.index.type in (str_type, unicode_type):
# obj[str] is probably doing a dict lookup
function = "__Pyx_PyObject_GetItemUnicode"
utility_code = UtilityCode.load_cached("DictGetItemUnicode", "ObjectHandling.c")
else: else:
function = "PyObject_GetItem" function = "PyObject_GetItem"
elif self.type.is_unicode_char and self.base.type is unicode_type: elif self.type.is_unicode_char and self.base.type is unicode_type:
assert self.index.type.is_int assert self.index.type.is_int
function = "__Pyx_GetItemInt_Unicode" function = "__Pyx_GetItemInt_Unicode"
error_value = '(Py_UCS4)-1' error_value = '(Py_UCS4)-1'
code.globalstate.use_utility_code( utility_code = UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c")
UtilityCode.load_cached("GetItemIntUnicode", "StringTools.c"))
elif self.base.type is bytearray_type: elif self.base.type is bytearray_type:
assert self.index.type.is_int assert self.index.type.is_int
assert self.type.is_int assert self.type.is_int
function = "__Pyx_GetItemInt_ByteArray" function = "__Pyx_GetItemInt_ByteArray"
error_value = '-1' error_value = '-1'
code.globalstate.use_utility_code( utility_code = UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c")
UtilityCode.load_cached("GetItemIntByteArray", "StringTools.c"))
elif not (self.base.type.is_cpp_class and self.exception_check): elif not (self.base.type.is_cpp_class and self.exception_check):
assert False, "unexpected type %s and base type %s for indexing" % ( assert False, "unexpected type %s and base type %s for indexing" % (
self.type, self.base.type) self.type, self.base.type)
if utility_code is not None:
code.globalstate.use_utility_code(utility_code)
if self.index.type.is_int: if self.index.type.is_int:
index_code = self.index.result() index_code = self.index.result()
else: else:
......
...@@ -262,8 +262,59 @@ static CYTHON_INLINE int __Pyx_IterFinish(void) { ...@@ -262,8 +262,59 @@ static CYTHON_INLINE int __Pyx_IterFinish(void) {
#endif #endif
} }
/////////////// DictGetItemUnicode.proto ///////////////
//@requires: DictGetItem
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS
static CYTHON_INLINE PyObject *__Pyx__PyDict_GetItemUnicode(PyObject *d, PyObject* key);
#define __Pyx_PyDict_GetItemUnicode(d, key) \
(likely(PyUnicode_CheckExact(key) && ((PyASCIIObject *) key)->hash != -1) ? \
__Pyx__PyDict_GetItemUnicode(d, key) : __Pyx_PyDict_GetItem(d, key))
#define __Pyx_PyObject_GetItemUnicode(obj, name) \
(likely(PyDict_CheckExact(obj)) ? \
__Pyx_PyDict_GetItemUnicode(obj, name) : PyObject_GetItem(obj, name))
#else /* Py < 3.5 */
#define __Pyx_PyDict_GetItemUnicode(d, key) __Pyx_PyDict_GetItem(d, key)
#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
#define __Pyx_PyObject_GetItemUnicode(obj, name) \
(likely(PyDict_CheckExact(obj)) ? \
__Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name))
#else
#define __Pyx_PyObject_GetItemUnicode(obj, name) PyObject_GetItem(obj, name)
#endif
#endif
/////////////// DictGetItemUnicode ///////////////
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS
static PyObject *__Pyx__PyDict_GetItemUnicode(PyObject *d, PyObject* key) {
PyObject *value;
value = __Pyx_PyDict_GetItemStr(d, key);
if (unlikely(!value)) {
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
Py_INCREF(value);
return value;
}
#endif
/////////////// DictGetItem.proto /////////////// /////////////// DictGetItem.proto ///////////////
#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key);/*proto*/
#else
#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
#endif
/////////////// DictGetItem ///////////////
#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value; PyObject *value;
...@@ -280,8 +331,6 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { ...@@ -280,8 +331,6 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
Py_INCREF(value); Py_INCREF(value);
return value; return value;
} }
#else
#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
#endif #endif
/////////////// GetItemInt.proto /////////////// /////////////// GetItemInt.proto ///////////////
......
...@@ -46,6 +46,72 @@ def test(dict d, index): ...@@ -46,6 +46,72 @@ def test(dict d, index):
""" """
return d[index] return d[index]
def getitem_str(dict d, obj, str index):
"""
>>> d = {'abc': 1, 'xyz': 2, None: 3}
>>> getitem_str(d, d, 'abc')
(1, 1)
>>> getitem_str(d, d, 'xyz')
(2, 2)
>>> getitem_str(d, d, None)
(3, 3)
>>> class GetItem(object):
... def __getitem__(self, name): return d[name]
>>> getitem_str(d, GetItem(), 'abc')
(1, 1)
>>> getitem_str(d, GetItem(), 'xyz')
(2, 2)
>>> getitem_str(d, GetItem(), None)
(3, 3)
>>> getitem_str(d, GetItem(), 'no')
Traceback (most recent call last):
KeyError: 'no'
>>> class GetItemFail(object):
... def __getitem__(self, name): raise ValueError("failed")
>>> getitem_str(d, GetItemFail(), 'abc')
Traceback (most recent call last):
ValueError: failed
>>> getitem_str(d, GetItemFail(), None)
Traceback (most recent call last):
ValueError: failed
"""
return d[index], obj[index]
def getitem_unicode(dict d, obj, unicode index):
"""
>>> d = {'abc': 1, 'xyz': 2, None: 3}
>>> getitem_unicode(d, d, u'abc')
(1, 1)
>>> getitem_unicode(d, d, u'xyz')
(2, 2)
>>> getitem_unicode(d, d, None)
(3, 3)
>>> class GetItem(object):
... def __getitem__(self, name): return d[name]
>>> getitem_unicode(d, GetItem(), u'abc')
(1, 1)
>>> getitem_unicode(d, GetItem(), u'xyz')
(2, 2)
>>> getitem_unicode(d, GetItem(), None)
(3, 3)
>>> try: getitem_unicode(d, GetItem(), u'no')
... except KeyError as exc: assert exc.args[0] == u'no', str(exc)
... else: assert False, "KeyError not raised"
>>> class GetItemFail(object):
... def __getitem__(self, name): raise ValueError("failed")
>>> getitem_unicode(d, GetItemFail(), u'abc')
Traceback (most recent call last):
ValueError: failed
"""
return d[index], obj[index]
def getitem_tuple(dict d, index): def getitem_tuple(dict d, index):
""" """
>>> d = {1: 1, (1,): 2} >>> d = {1: 1, (1,): 2}
...@@ -54,6 +120,7 @@ def getitem_tuple(dict d, index): ...@@ -54,6 +120,7 @@ def getitem_tuple(dict d, index):
""" """
return d[index], d[index,] return d[index], d[index,]
def getitem_in_condition(dict d, key, expected_result): def getitem_in_condition(dict d, key, expected_result):
""" """
>>> d = dict(a=1, b=2) >>> d = dict(a=1, b=2)
...@@ -62,6 +129,7 @@ def getitem_in_condition(dict d, key, expected_result): ...@@ -62,6 +129,7 @@ def getitem_in_condition(dict d, key, expected_result):
""" """
return d[key] is expected_result or d[key] == expected_result return d[key] is expected_result or d[key] == expected_result
@cython.test_fail_if_path_exists('//NoneCheckNode') @cython.test_fail_if_path_exists('//NoneCheckNode')
def getitem_not_none(dict d not None, key): def getitem_not_none(dict d not None, key):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment