Author: Maciej Fijalkowski <[email protected]>
Branch: rordereddict
Changeset: r67669:9f44c1e921fa
Date: 2013-10-29 00:05 +0200
http://bitbucket.org/pypy/pypy/changeset/9f44c1e921fa/
Log: Provide OrderedDict implemention for RPython, stolen from rdict-
experiments-3 branch. Note that two new tests are skipped, because
rdict-experiments-3 branch has the official version of this file
diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -6,7 +6,8 @@
import operator
from rpython.tool.pairtype import pair, pairtype
from rpython.annotator.model import SomeObject, SomeInteger, SomeBool, s_Bool
-from rpython.annotator.model import SomeString, SomeChar, SomeList, SomeDict
+from rpython.annotator.model import SomeString, SomeChar, SomeList, SomeDict,\
+ SomeOrderedDict
from rpython.annotator.model import SomeUnicodeCodePoint, SomeUnicodeString
from rpython.annotator.model import SomeTuple, SomeImpossibleValue,
s_ImpossibleValue
from rpython.annotator.model import SomeInstance, SomeBuiltin, SomeIterator
@@ -581,7 +582,8 @@
class __extend__(pairtype(SomeDict, SomeDict)):
def union((dic1, dic2)):
- return SomeDict(dic1.dictdef.union(dic2.dictdef))
+ assert dic1.__class__ == dic2.__class__
+ return dic1.__class__(dic1.dictdef.union(dic2.dictdef))
class __extend__(pairtype(SomeDict, SomeObject)):
@@ -840,6 +842,7 @@
_make_none_union('SomeString', 'no_nul=obj.no_nul, can_be_None=True')
_make_none_union('SomeUnicodeString', 'can_be_None=True')
_make_none_union('SomeList', 'obj.listdef')
+_make_none_union('SomeOrderedDict', 'obj.dictdef')
_make_none_union('SomeDict', 'obj.dictdef')
_make_none_union('SomeWeakRef', 'obj.classdef')
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -5,9 +5,10 @@
from __future__ import absolute_import
import sys, types, inspect, weakref
+from collections import OrderedDict
from rpython.flowspace.model import Constant
-from rpython.annotator.model import (
+from rpython.annotator.model import (SomeOrderedDict,
SomeString, SomeChar, SomeFloat, SomePtr, unionof, SomeInstance, SomeDict,
SomeBuiltin, SomePBC, SomeInteger, TLS, SomeAddress, SomeUnicodeCodePoint,
s_None, s_ImpossibleValue, SomeLLADTMeth, SomeBool, SomeTuple,
@@ -370,7 +371,7 @@
for e in x:
listdef.generalize(self.immutablevalue(e, False))
result = SomeList(listdef)
- elif tp is dict or tp is r_dict:
+ elif tp is dict or tp is r_dict or tp is OrderedDict:
if need_const:
key = Constant(x)
try:
@@ -412,7 +413,10 @@
dictdef.generalize_key(self.immutablevalue(ek, False))
dictdef.generalize_value(self.immutablevalue(ev, False))
dictdef.seen_prebuilt_key(ek)
- result = SomeDict(dictdef)
+ if tp is OrderedDict:
+ result = SomeOrderedDict(dictdef)
+ else:
+ result = SomeDict(dictdef)
elif tp is weakref.ReferenceType:
x1 = x()
if x1 is None:
diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py
--- a/rpython/annotator/builtin.py
+++ b/rpython/annotator/builtin.py
@@ -2,11 +2,13 @@
Built-in functions.
"""
import sys
+from collections import OrderedDict
from rpython.annotator.model import (
SomeInteger, SomeObject, SomeChar, SomeBool, SomeString, SomeTuple, s_Bool,
SomeUnicodeCodePoint, SomeAddress, SomeFloat, unionof, SomeUnicodeString,
SomePBC, SomeInstance, SomeDict, SomeList, SomeWeakRef, SomeIterator,
+ SomeOrderedDict,
SomeByteArray, annotation_to_lltype, lltype_to_annotation,
ll_to_annotation, add_knowntypedata, s_ImpossibleValue,)
from rpython.annotator.bookkeeper import getbookkeeper
@@ -357,6 +359,7 @@
BUILTIN_ANALYZERS[rpython.rlib.rarithmetic.longlongmask] = rarith_longlongmask
BUILTIN_ANALYZERS[rpython.rlib.objectmodel.instantiate] = robjmodel_instantiate
BUILTIN_ANALYZERS[rpython.rlib.objectmodel.r_dict] = robjmodel_r_dict
+BUILTIN_ANALYZERS[OrderedDict] = lambda :
SomeOrderedDict(getbookkeeper().getdictdef())
BUILTIN_ANALYZERS[rpython.rlib.objectmodel.hlinvoke] = robjmodel_hlinvoke
BUILTIN_ANALYZERS[rpython.rlib.objectmodel.keepalive_until_here] =
robjmodel_keepalive_until_here
BUILTIN_ANALYZERS[rpython.rtyper.lltypesystem.llmemory.cast_ptr_to_adr] =
llmemory_cast_ptr_to_adr
diff --git a/rpython/annotator/model.py b/rpython/annotator/model.py
--- a/rpython/annotator/model.py
+++ b/rpython/annotator/model.py
@@ -32,6 +32,7 @@
import inspect
import weakref
from types import BuiltinFunctionType, MethodType
+from collections import OrderedDict
import rpython
from rpython.tool import descriptor
@@ -355,6 +356,18 @@
else:
return '{...%s...}' % (len(const),)
+class SomeOrderedDict(SomeDict):
+ knowntype = OrderedDict
+
+ def method_copy(dct):
+ return SomeOrderedDict(dct.dictdef)
+
+ def method_update(dct1, dct2):
+ if s_None.contains(dct2):
+ return SomeImpossibleValue()
+ assert isinstance(dct2, SomeOrderedDict), "OrderedDict.update(dict)
not allowed"
+ dct1.dictdef.union(dct2.dictdef)
+
class SomeIterator(SomeObject):
"Stands for an iterator returning objects from a given container."
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -194,10 +194,11 @@
return True
-class DictRepr(AbstractDictRepr):
+class OrderedDictRepr(AbstractDictRepr):
def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue,
- custom_eq_hash=None):
+ custom_eq_hash=None, force_non_null=False):
+ assert not force_non_null
self.rtyper = rtyper
self.finalized = False
self.DICT = lltype.GcForwardReference()
@@ -389,7 +390,7 @@
v_res = hop.gendirectcall(target, *v_args)
return self.recast_value(hop.llops, v_res)
-class __extend__(pairtype(DictRepr, rmodel.Repr)):
+class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)):
def rtype_getitem((r_dict, r_key), hop):
v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
@@ -419,7 +420,7 @@
hop.exception_is_here()
return hop.gendirectcall(ll_dict_contains, v_dict, v_key)
-class __extend__(pairtype(DictRepr, DictRepr)):
+class __extend__(pairtype(OrderedDictRepr, OrderedDictRepr)):
def convert_from_to((r_dict1, r_dict2), v, llops):
# check that we don't convert from Dicts with
# different key/value types
diff --git a/rpython/rtyper/rbuiltin.py b/rpython/rtyper/rbuiltin.py
--- a/rpython/rtyper/rbuiltin.py
+++ b/rpython/rtyper/rbuiltin.py
@@ -1,3 +1,5 @@
+from collections import OrderedDict
+
from rpython.annotator import model as annmodel
from rpython.flowspace.model import Constant
from rpython.rlib import rarithmetic, objectmodel
@@ -726,10 +728,19 @@
raise TyperError("hasattr is only suported on a constant")
+def rtype_ordered_dict(hop):
+ from rpython.rtyper.lltypesystem.rordereddict import ll_newdict
+
+ hop.exception_cannot_occur()
+ r_dict = hop.r_result
+ cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
+ return hop.gendirectcall(ll_newdict, cDICT)
+
BUILTIN_TYPER[objectmodel.instantiate] = rtype_instantiate
BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance
BUILTIN_TYPER[hasattr] = rtype_builtin_hasattr
BUILTIN_TYPER[objectmodel.r_dict] = rtype_r_dict
+BUILTIN_TYPER[OrderedDict] = rtype_ordered_dict
# _________________________________________________________________
# weakrefs
diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py
--- a/rpython/rtyper/rdict.py
+++ b/rpython/rtyper/rdict.py
@@ -4,8 +4,12 @@
class __extend__(annmodel.SomeDict):
+ def get_dict_repr(self):
+ from rpython.rtyper.lltypesystem.rdict import DictRepr
+
+ return DictRepr
+
def rtyper_makerepr(self, rtyper):
- from rpython.rtyper.lltypesystem.rdict import DictRepr
dictkey = self.dictdef.dictkey
dictvalue = self.dictdef.dictvalue
s_key = dictkey.s_value
@@ -16,7 +20,7 @@
rtyper.getrepr(dictkey.s_rdict_hashfn))
else:
custom_eq_hash = None
- return DictRepr(rtyper, lambda: rtyper.getrepr(s_key),
+ return self.get_dict_repr()(rtyper, lambda: rtyper.getrepr(s_key),
lambda: rtyper.getrepr(s_value), dictkey, dictvalue,
custom_eq_hash, force_non_null)
@@ -25,6 +29,11 @@
self.dictdef.dictvalue.dont_change_any_more = True
return (self.__class__, self.dictdef.dictkey, self.dictdef.dictvalue)
+class __extend__(annmodel.SomeOrderedDict):
+ def get_dict_repr(self):
+ from rpython.rtyper.lltypesystem.rordereddict import OrderedDictRepr
+
+ return OrderedDictRepr
class AbstractDictRepr(rmodel.Repr):
diff --git a/rpython/rtyper/test/test_rdict.py
b/rpython/rtyper/test/test_rdict.py
--- a/rpython/rtyper/test/test_rdict.py
+++ b/rpython/rtyper/test/test_rdict.py
@@ -22,11 +22,11 @@
yield x
-class TestRdict(BaseRtypingTest):
-
+class BaseTestRDict(BaseRtypingTest):
def test_dict_creation(self):
def createdict(i):
- d = {'hello' : i}
+ d = self.newdict()
+ d['hello'] = i
return d['hello']
res = self.interpret(createdict, [42])
@@ -34,7 +34,8 @@
def test_dict_getitem_setitem(self):
def func(i):
- d = {'hello' : i}
+ d = self.newdict()
+ d['hello'] = i
d['world'] = i + 1
return d['hello'] * d['world']
res = self.interpret(func, [6])
@@ -42,7 +43,8 @@
def test_dict_getitem_keyerror(self):
def func(i):
- d = {'hello' : i}
+ d = self.newdict()
+ d['hello'] = i
try:
return d['world']
except KeyError:
@@ -52,7 +54,8 @@
def test_dict_del_simple(self):
def func(i):
- d = {'hello' : i}
+ d = self.newdict()
+ d['hello'] = i
d['world'] = i + 1
del d['hello']
return len(d)
@@ -61,7 +64,8 @@
def test_dict_clear(self):
def func(i):
- d = {'abc': i}
+ d = self.newdict()
+ d['abc'] = i
d['def'] = i+1
d.clear()
d['ghi'] = i+2
@@ -72,7 +76,8 @@
def test_empty_strings(self):
def func(i):
- d = {'' : i}
+ d = self.newdict()
+ d[''] = i
del d['']
try:
d['']
@@ -84,7 +89,8 @@
assert res == 1
def func(i):
- d = {'' : i}
+ d = self.newdict()
+ d[''] = i
del d['']
d[''] = i + 1
return len(d)
@@ -94,9 +100,10 @@
def test_dict_bool(self):
def func(i):
if i:
- d = {}
+ d = self.newdict()
else:
- d = {i: i+1}
+ d = self.newdict()
+ d[i] = i+1
if d:
return i
else:
@@ -106,17 +113,20 @@
def test_contains(self):
def func(x, y):
- d = {x: x+1}
+ d = self.newdict()
+ d[x] = x+1
return y in d
assert self.interpret(func, [42, 0]) == False
assert self.interpret(func, [42, 42]) == True
def test_contains_2(self):
- d = {'5': None, '7': None}
+ d = self.newdict()
+ d['5'] = None
+ d['7'] = None
def func(x):
return chr(x) in d
- #assert self.interpret(func, [ord('5')]) == True
- #assert self.interpret(func, [ord('6')]) == False
+ assert self.interpret(func, [ord('5')]) == True
+ assert self.interpret(func, [ord('6')]) == False
def func(n):
return str(n) in d
@@ -124,7 +134,7 @@
def test_dict_iteration(self):
def func(i, j):
- d = {}
+ d = self.newdict()
d['hello'] = i
d['world'] = j
k = 1
@@ -136,7 +146,7 @@
def test_dict_itermethods(self):
def func():
- d = {}
+ d = self.newdict()
d['hello'] = 6
d['world'] = 7
k1 = k2 = k3 = 1
@@ -151,19 +161,9 @@
res = self.interpret(func, [])
assert res == 42 + 42 + 42
- def test_two_dicts_with_different_value_types(self):
- def func(i):
- d1 = {}
- d1['hello'] = i + 1
- d2 = {}
- d2['world'] = d1
- return d2['world']['hello']
- res = self.interpret(func, [5])
- assert res == 6
-
def test_dict_get(self):
def func():
- dic = {}
+ dic = self.newdict()
x1 = dic.get('hi', 42)
dic['blah'] = 1 # XXX this triggers type determination
x2 = dic.get('blah', 2)
@@ -174,7 +174,7 @@
def test_dict_get_empty(self):
def func():
# this time without writing to the dict
- dic = {}
+ dic = self.newdict()
x1 = dic.get('hi', 42)
x2 = dic.get('blah', 2)
return x1 * 10 + x2
@@ -183,14 +183,14 @@
def test_dict_setdefault(self):
def f():
- d = {}
+ d = self.newdict()
d.setdefault('a', 2)
return d['a']
res = self.interpret(f, ())
assert res == 2
def f():
- d = {}
+ d = self.newdict()
d.setdefault('a', 2)
x = d.setdefault('a', -3)
return x
@@ -200,7 +200,9 @@
def test_dict_copy(self):
def func():
# XXX this does not work if we use chars, only!
- dic = {'ab':1, 'b':2}
+ dic = self.newdict()
+ dic['ab'] = 1
+ dic['b'] = 2
d2 = dic.copy()
ok = 1
for key in d2:
@@ -215,8 +217,12 @@
def test_dict_update(self):
def func():
- dic = {'ab':1000, 'b':200}
- d2 = {'b':30, 'cb':4}
+ dic = self.newdict()
+ dic['ab'] = 1000
+ dic['b'] = 200
+ d2 = self.newdict()
+ d2['b'] = 30
+ d2['cb'] = 4
dic.update(d2)
ok = len(dic) == 3
sum = ok
@@ -228,7 +234,9 @@
def test_dict_keys(self):
def func():
- dic = {' 4':1000, ' 8':200}
+ dic = self.newdict()
+ dic[' 4'] = 1000
+ dic[' 8'] = 200
keys = dic.keys()
return ord(keys[0][1]) + ord(keys[1][1]) - 2*ord('0') + len(keys)
res = self.interpret(func, ())#, view=True)
@@ -240,8 +248,11 @@
class A(Empty):
pass
def func():
- dic0 = {Empty(): 2}
- dic = {A(): 1, A(): 2}
+ dic0 = self.newdict()
+ dic0[Empty()] = 2
+ dic = self.newdict()
+ dic[A()] = 1
+ dic[A()] = 2
keys = dic.keys()
return (isinstance(keys[1], A))*2+(isinstance(keys[0],A))
res = self.interpret(func, [])
@@ -253,8 +264,11 @@
class A(Empty):
pass
def func():
- dic0 = {Empty(): 2}
- dic = {A(): 1, A(): 2}
+ dic0 = self.newdict()
+ dic0[Empty()] = 2
+ dic = self.newdict()
+ dic[A()] = 1
+ dic[A()] = 2
a = 0
for k in dic.iterkeys():
a += isinstance(k, A)
@@ -264,7 +278,9 @@
def test_dict_values(self):
def func():
- dic = {' 4':1000, ' 8':200}
+ dic = self.newdict()
+ dic[' 4'] = 1000
+ dic[' 8'] = 200
values = dic.values()
return values[0] + values[1] + len(values)
res = self.interpret(func, ())
@@ -274,7 +290,9 @@
class A:
pass
def func():
- dic = {1: A(), 2: A()}
+ dic = self.newdict()
+ dic[1] = A()
+ dic[2] = A()
vals = dic.values()
return (isinstance(vals[1], A))*2+(isinstance(vals[0],A))
res = self.interpret(func, [])
@@ -284,7 +302,9 @@
class A:
pass
def func():
- dic = {1: A(), 2: A()}
+ dic = self.newdict()
+ dic[1] = A()
+ dic[2] = A()
a = 0
for v in dic.itervalues():
a += isinstance(v, A)
@@ -300,8 +320,11 @@
class B(Empty):
pass
def func():
- dic0 = {Empty(): 2}
- dic = {B(): A(), B(): A()}
+ dic0 = self.newdict()
+ dic0[Empty()] = A()
+ dic = self.newdict()
+ dic[B()] = A()
+ dic[B()] = A()
items = dic.items()
b = 0
a = 0
@@ -320,8 +343,11 @@
class B(Empty):
pass
def func():
- dic0 = {Empty(): 2}
- dic = {B(): A(), B(): A()}
+ dic0 = self.newdict()
+ dic0[Empty()] = A()
+ dic = self.newdict()
+ dic[B()] = A()
+ dic[B()] = A()
b = 0
a = 0
for k, v in dic.iteritems():
@@ -333,7 +359,9 @@
def test_dict_items(self):
def func():
- dic = {' 4':1000, ' 8':200}
+ dic = self.newdict()
+ dic[' 4'] = 1000
+ dic[' 8'] = 200
items = dic.items()
res = len(items)
for key, value in items:
@@ -344,13 +372,17 @@
def test_dict_contains(self):
def func():
- dic = {' 4':1000, ' 8':200}
+ dic = self.newdict()
+ dic[' 4'] = 1000
+ dic[' 8'] = 200
return ' 4' in dic and ' 9' not in dic
res = self.interpret(func, ())
assert res is True
def test_dict_contains_with_constant_dict(self):
- dic = {'4':1000, ' 8':200}
+ dic = self.newdict()
+ dic['4'] = 1000
+ dic['8'] = 200
def func(i):
return chr(i) in dic
res = self.interpret(func, [ord('4')])
@@ -367,7 +399,9 @@
a = A()
a.d = None
if n > 0:
- a.d = {str(n): 1, "42": 2}
+ a.d = self.newdict()
+ a.d[str(n)] = 1
+ a.d["42"] = 2
del a.d["42"]
return negate(a.d)
res = self.interpret(func, [10])
@@ -379,7 +413,8 @@
def test_int_dict(self):
def func(a, b):
- dic = {12: 34}
+ dic = self.newdict()
+ dic[12] = 34
dic[a] = 1000
return dic.get(b, -123)
res = self.interpret(func, [12, 12])
@@ -403,7 +438,7 @@
def f():
a = A()
b = B()
- d = {}
+ d = self.newdict()
d[b] = 7
d[a] = 3
return len(d) + d[a] + d[b]
@@ -411,7 +446,9 @@
assert res == 12
def test_captured_get(self):
- get = {1:2}.get
+ d = self.newdict()
+ d[1] = 2
+ get = d.get
def f():
return get(1, 3)+get(2, 4)
res = self.interpret(f, [])
@@ -431,40 +468,21 @@
def f():
lst = [A()]
res1 = A() in lst
- d2 = {B(): None, B(): None}
+ d2 = self.newdict()
+ d2[B()] = None
+ d2[B()] = None
return res1+len(d2)
res = self.interpret(f, [])
assert res == 2
-
- def test_type_erase(self):
- class A(object):
- pass
- class B(object):
- pass
-
- def f():
- return {A(): B()}, {B(): A()}
-
- t = TranslationContext()
- s = t.buildannotator().build_types(f, [])
- rtyper = t.buildrtyper()
- rtyper.specialize()
-
- s_AB_dic = s.items[0]
- s_BA_dic = s.items[1]
-
- r_AB_dic = rtyper.getrepr(s_AB_dic)
- r_BA_dic = rtyper.getrepr(s_AB_dic)
-
- assert r_AB_dic.lowleveltype == r_BA_dic.lowleveltype
-
def test_identity_hash_is_fast(self):
class A(object):
pass
def f():
- return {A(): 1}
+ d = self.newdict()
+ d[A()] = 1
+ return d
t = TranslationContext()
s = t.buildannotator().build_types(f, [])
@@ -476,7 +494,7 @@
def test_tuple_dict(self):
def f(i):
- d = {}
+ d = self.newdict()
d[(1, 4.5, (str(i), 2), 2)] = 4
d[(1, 4.5, (str(i), 2), 3)] = 6
return d[(1, 4.5, (str(i), 2), i)]
@@ -486,9 +504,9 @@
def test_dict_of_dict(self):
def f(n):
- d = {}
+ d = self.newdict()
d[5] = d
- d[6] = {}
+ d[6] = self.newdict()
return len(d[n])
res = self.interpret(f, [5])
@@ -504,10 +522,9 @@
pass
def f(i):
- d = {
- A: 3,
- B: 4,
- }
+ d = self.newdict()
+ d[A] = 3
+ d[B] = 4
if i:
cls = A
else:
@@ -526,7 +543,9 @@
class B(A):
pass
- d = {(A, 3): 3, (B, 0): 4}
+ d = self.newdict()
+ d[(A, 3)] = 3
+ d[(B, 0)] = 4
def f(i):
if i:
@@ -553,7 +572,9 @@
return 42
return -1
def g(n):
- d = {1: n, 2: 2*n}
+ d = self.newdict()
+ d[1] = n
+ d[2] = 2*n
return f(d)
res = self.interpret(g, [3])
assert res == 6
@@ -566,7 +587,8 @@
return 42
return -1
def g(n):
- d = {1: n}
+ d = self.newdict()
+ d[1] = n
f(d)
return d[2]
res = self.interpret(g, [3])
@@ -610,7 +632,10 @@
def test_resize_during_iteration(self):
def func():
- d = {5: 1, 6: 2, 7: 3}
+ d = self.newdict()
+ d[5] = 1
+ d[6] = 2
+ d[7] = 3
try:
for key, value in d.iteritems():
d[key^16] = value*2
@@ -625,14 +650,21 @@
def test_change_during_iteration(self):
def func():
- d = {'a': 1, 'b': 2}
+ d = self.newdict()
+ d['a'] = 1
+ d['b'] = 2
for key in d:
d[key] = 42
return d['a']
assert self.interpret(func, []) == 42
def test_dict_of_floats(self):
- d = {3.0: 42, 3.1: 43, 3.2: 44, 3.3: 45, 3.4: 46}
+ d = self.newdict()
+ d[3.0] = 42
+ d[3.1] = 43
+ d[3.2] = 44
+ d[3.3] = 45
+ d[3.4] = 46
def fn(f):
return d[f]
@@ -643,7 +675,9 @@
for r_t in [r_uint, r_longlong, r_ulonglong]:
if r_t is r_int:
continue # for 64-bit platforms: skip r_longlong
- d = {r_t(2): 3, r_t(4): 5}
+ d = self.newdict()
+ d[r_t(2)] = 3
+ d[r_t(4)] = 5
def fn(x, y):
d[r_t(x)] = 123
return d[r_t(y)]
@@ -654,7 +688,7 @@
def test_dict_popitem(self):
def func():
- d = {}
+ d = self.newdict()
d[5] = 2
d[6] = 3
k1, v1 = d.popitem()
@@ -698,7 +732,7 @@
def test_dict_pop(self):
def f(n, default):
- d = {}
+ d = self.newdict()
d[2] = 3
d[4] = 5
if default == -1:
@@ -720,7 +754,7 @@
class A(object):
pass
def f(n):
- d = {}
+ d = self.newdict()
d[2] = A()
x = d.pop(n, None)
if x is None:
@@ -734,7 +768,8 @@
def test_dict_but_not_with_char_keys(self):
def func(i):
- d = {'h': i}
+ d = self.newdict()
+ d['h'] = i
try:
return d['hello']
except KeyError:
@@ -752,7 +787,7 @@
def func(c1, c2):
c1 = chr(c1)
c2 = chr(c2)
- d = {}
+ d = self.newdict()
d[c1] = 1
d[c2] = 2
del d[c1]
@@ -806,27 +841,6 @@
count_frees += 1
assert count_frees >= 3
- def test_dict_resize(self):
- # XXX we no longer automatically resize on 'del'. We need to
- # hack a bit in this test to trigger a resize by continuing to
- # fill the dict's table while keeping the actual size very low
- # in order to force a resize to shrink the table back
- def func(want_empty):
- d = {}
- for i in range(rdict.DICT_INITSIZE << 1):
- d[chr(ord('a') + i)] = i
- if want_empty:
- for i in range(rdict.DICT_INITSIZE << 1):
- del d[chr(ord('a') + i)]
- for i in range(rdict.DICT_INITSIZE << 3):
- d[chr(ord('A') - i)] = i
- del d[chr(ord('A') - i)]
- return d
- res = self.interpret(func, [0])
- assert len(res.entries) > rdict.DICT_INITSIZE
- res = self.interpret(func, [1])
- assert len(res.entries) == rdict.DICT_INITSIZE
-
def test_dict_valid_resize(self):
# see if we find our keys after resize
def func():
@@ -843,6 +857,212 @@
# ____________________________________________________________
+ def test_dict_of_addresses(self):
+ from rpython.rtyper.lltypesystem import llmemory
+ TP = lltype.Struct('x')
+ a = lltype.malloc(TP, flavor='raw', immortal=True)
+ b = lltype.malloc(TP, flavor='raw', immortal=True)
+
+ def func(i):
+ d = self.newdict()
+ d[llmemory.cast_ptr_to_adr(a)] = 123
+ d[llmemory.cast_ptr_to_adr(b)] = 456
+ if i > 5:
+ key = llmemory.cast_ptr_to_adr(a)
+ else:
+ key = llmemory.cast_ptr_to_adr(b)
+ return d[key]
+
+ assert self.interpret(func, [3]) == 456
+
+ def test_prebuilt_list_of_addresses(self):
+ from rpython.rtyper.lltypesystem import llmemory
+
+ TP = lltype.Struct('x', ('y', lltype.Signed))
+ a = lltype.malloc(TP, flavor='raw', immortal=True)
+ b = lltype.malloc(TP, flavor='raw', immortal=True)
+ c = lltype.malloc(TP, flavor='raw', immortal=True)
+ a_a = llmemory.cast_ptr_to_adr(a)
+ a0 = llmemory.cast_ptr_to_adr(a)
+ assert a_a is not a0
+ assert a_a == a0
+ a_b = llmemory.cast_ptr_to_adr(b)
+ a_c = llmemory.cast_ptr_to_adr(c)
+
+ d = self.newdict()
+ d[a_a] = 3
+ d[a_b] = 4
+ d[a_c] = 5
+ d[a0] = 8
+
+ def func(i):
+ if i == 0:
+ ptr = a
+ else:
+ ptr = b
+ return d[llmemory.cast_ptr_to_adr(ptr)]
+
+ py.test.raises(TypeError, self.interpret, func, [0])
+
+ def test_dict_of_voidp(self):
+ def func():
+ d = self.newdict()
+ handle = lltype.nullptr(rffi.VOIDP.TO)
+ # Use a negative key, so the dict implementation uses
+ # the value as a marker for empty entries
+ d[-1] = handle
+ return len(d)
+
+ assert self.interpret(func, []) == 1
+ from rpython.translator.c.test.test_genc import compile
+ f = compile(func, [])
+ res = f()
+ assert res == 1
+
+ def test_dict_with_SHORT_keys(self):
+ def func(x):
+ d = self.newdict()
+ d[rffi.cast(rffi.SHORT, 42)] = 123
+ d[rffi.cast(rffi.SHORT, -43)] = 321
+ return d[rffi.cast(rffi.SHORT, x)]
+
+ assert self.interpret(func, [42]) == 123
+ assert self.interpret(func, [2**16 - 43]) == 321
+
+ def test_dict_with_bool_keys(self):
+ def func(x):
+ d = self.newdict()
+ d[False] = 123
+ d[True] = 321
+ return d[x == 42]
+
+ assert self.interpret(func, [5]) == 123
+ assert self.interpret(func, [42]) == 321
+
+ def test_nonnull_hint(self):
+ def eq(a, b):
+ return a == b
+ def rhash(a):
+ return 3
+
+ def func(i):
+ d = r_dict(eq, rhash, force_non_null=True)
+ if not i:
+ d[None] = i
+ else:
+ d[str(i)] = i
+ return "12" in d, d
+
+ llres = self.interpret(func, [12])
+ assert llres.item0 == 1
+ DICT = lltype.typeOf(llres.item1)
+ assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key',
'value']
+
+ def test_memoryerror_should_not_insert(self):
+ # This shows a misbehaviour that also exists in CPython 2.7, but not
+ # any more in CPython 3.3. The behaviour is that even if a dict
+ # insertion raises MemoryError, the new item is still inserted.
+ # If we catch the MemoryError, we can keep inserting new items until
+ # the dict table is completely full. Then the next insertion loops
+ # forever. This test only checks that after a MemoryError the
+ # new item was not inserted.
+ def _check_small_range(self, n):
+ if n >= 128:
+ raise MemoryError
+ return range(n)
+ original_check_range = lltype._array._check_range
+ try:
+ lltype._array._check_range = _check_small_range
+ #
+ def do_insert(d, i):
+ d[i] = i
+ def func():
+ d = self.newdict()
+ i = 0
+ while True:
+ try:
+ do_insert(d, i)
+ except MemoryError:
+ return (i in d)
+ i += 1
+ res = self.interpret(func, [])
+ assert res == 0
+ #
+ finally:
+ lltype._array._check_range = original_check_range
+
+ def test_dict_with_none_key(self):
+ def func(i):
+ d = self.newdict()
+ d[None] = i
+ return d[None]
+ res = self.interpret(func, [42])
+ assert res == 42
+
+
+class TestRDict(BaseTestRDict):
+ @staticmethod
+ def newdict():
+ return {}
+
+ def test_two_dicts_with_different_value_types(self):
+ def func(i):
+ d1 = {}
+ d1['hello'] = i + 1
+ d2 = {}
+ d2['world'] = d1
+ return d2['world']['hello']
+ res = self.interpret(func, [5])
+ assert res == 6
+
+ def test_type_erase(self):
+ class A(object):
+ pass
+ class B(object):
+ pass
+
+ def f():
+ d = {}
+ d[A()] = B()
+ d2 = {}
+ d2[B()] = A()
+ return d, d2
+
+ t = TranslationContext()
+ s = t.buildannotator().build_types(f, [])
+ rtyper = t.buildrtyper()
+ rtyper.specialize()
+
+ s_AB_dic = s.items[0]
+ s_BA_dic = s.items[1]
+
+ r_AB_dic = rtyper.getrepr(s_AB_dic)
+ r_BA_dic = rtyper.getrepr(s_AB_dic)
+
+ assert r_AB_dic.lowleveltype == r_BA_dic.lowleveltype
+
+
+ def test_dict_resize(self):
+ # XXX we no longer automatically resize on 'del'. We need to
+ # hack a bit in this test to trigger a resize by continuing to
+ # fill the dict's table while keeping the actual size very low
+ # in order to force a resize to shrink the table back
+ def func(want_empty):
+ d = self.newdict()
+ for i in range(rdict.DICT_INITSIZE << 1):
+ d[chr(ord('a') + i)] = i
+ if want_empty:
+ for i in range(rdict.DICT_INITSIZE << 1):
+ del d[chr(ord('a') + i)]
+ for i in range(rdict.DICT_INITSIZE << 3):
+ d[chr(ord('A') - i)] = i
+ del d[chr(ord('A') - i)]
+ return d
+ res = self.interpret(func, [0])
+ assert len(res.entries) > rdict.DICT_INITSIZE
+ res = self.interpret(func, [1])
+ assert len(res.entries) == rdict.DICT_INITSIZE
+
def test_opt_nullkeymarker(self):
def f():
d = {"hello": None}
@@ -940,145 +1160,6 @@
assert lltype.typeOf(res.item1) == lltype.typeOf(res.item2)
assert lltype.typeOf(res.item1) == lltype.typeOf(res.item3)
- def test_dict_of_addresses(self):
- from rpython.rtyper.lltypesystem import llmemory
- TP = lltype.Struct('x')
- a = lltype.malloc(TP, flavor='raw', immortal=True)
- b = lltype.malloc(TP, flavor='raw', immortal=True)
-
- def func(i):
- d = {}
- d[llmemory.cast_ptr_to_adr(a)] = 123
- d[llmemory.cast_ptr_to_adr(b)] = 456
- if i > 5:
- key = llmemory.cast_ptr_to_adr(a)
- else:
- key = llmemory.cast_ptr_to_adr(b)
- return d[key]
-
- assert self.interpret(func, [3]) == 456
-
- def test_prebuilt_list_of_addresses(self):
- from rpython.rtyper.lltypesystem import llmemory
-
- TP = lltype.Struct('x', ('y', lltype.Signed))
- a = lltype.malloc(TP, flavor='raw', immortal=True)
- b = lltype.malloc(TP, flavor='raw', immortal=True)
- c = lltype.malloc(TP, flavor='raw', immortal=True)
- a_a = llmemory.cast_ptr_to_adr(a)
- a0 = llmemory.cast_ptr_to_adr(a)
- assert a_a is not a0
- assert a_a == a0
- a_b = llmemory.cast_ptr_to_adr(b)
- a_c = llmemory.cast_ptr_to_adr(c)
-
- d = {a_a: 3, a_b: 4, a_c: 5}
- d[a0] = 8
-
- def func(i):
- if i == 0:
- ptr = a
- else:
- ptr = b
- return d[llmemory.cast_ptr_to_adr(ptr)]
-
- py.test.raises(TypeError, self.interpret, func, [0])
-
- def test_dict_of_voidp(self):
- def func():
- d = {}
- handle = lltype.nullptr(rffi.VOIDP.TO)
- # Use a negative key, so the dict implementation uses
- # the value as a marker for empty entries
- d[-1] = handle
- return len(d)
-
- assert self.interpret(func, []) == 1
- from rpython.translator.c.test.test_genc import compile
- f = compile(func, [])
- res = f()
- assert res == 1
-
- def test_dict_with_SHORT_keys(self):
- def func(x):
- d = {}
- d[rffi.cast(rffi.SHORT, 42)] = 123
- d[rffi.cast(rffi.SHORT, -43)] = 321
- return d[rffi.cast(rffi.SHORT, x)]
-
- assert self.interpret(func, [42]) == 123
- assert self.interpret(func, [2**16 - 43]) == 321
-
- def test_dict_with_bool_keys(self):
- def func(x):
- d = {}
- d[False] = 123
- d[True] = 321
- return d[x == 42]
-
- assert self.interpret(func, [5]) == 123
- assert self.interpret(func, [42]) == 321
-
- def test_nonnull_hint(self):
- def eq(a, b):
- return a == b
- def rhash(a):
- return 3
-
- def func(i):
- d = r_dict(eq, rhash, force_non_null=True)
- if not i:
- d[None] = i
- else:
- d[str(i)] = i
- return "12" in d, d
-
- llres = self.interpret(func, [12])
- assert llres.item0 == 1
- DICT = lltype.typeOf(llres.item1)
- assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key',
'value']
-
- def test_memoryerror_should_not_insert(self):
- # This shows a misbehaviour that also exists in CPython 2.7, but not
- # any more in CPython 3.3. The behaviour is that even if a dict
- # insertion raises MemoryError, the new item is still inserted.
- # If we catch the MemoryError, we can keep inserting new items until
- # the dict table is completely full. Then the next insertion loops
- # forever. This test only checks that after a MemoryError the
- # new item was not inserted.
- def _check_small_range(self, n):
- if n >= 128:
- raise MemoryError
- return range(n)
- original_check_range = lltype._array._check_range
- try:
- lltype._array._check_range = _check_small_range
- #
- def do_insert(d, i):
- d[i] = i
- def func():
- d = {}
- i = 0
- while True:
- try:
- do_insert(d, i)
- except MemoryError:
- return (i in d)
- i += 1
- res = self.interpret(func, [])
- assert res == 0
- #
- finally:
- lltype._array._check_range = original_check_range
-
- def test_dict_with_none_key(self):
- def func(i):
- d = {None: i}
- return d[None]
- res = self.interpret(func, [42])
- assert res == 42
-
-
class TestStress:
def test_stress(self):
@@ -1193,3 +1274,4 @@
print 'current dict length:', referencelength
assert l_dict.num_items == referencelength
complete_check()
+
diff --git a/rpython/rtyper/test/test_rordereddict.py
b/rpython/rtyper/test/test_rordereddict.py
--- a/rpython/rtyper/test/test_rordereddict.py
+++ b/rpython/rtyper/test/test_rordereddict.py
@@ -1,9 +1,11 @@
import py
+from collections import OrderedDict
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.lltypesystem import rordereddict, rstr
from rpython.rlib.rarithmetic import intmask
from rpython.rtyper.annlowlevel import llstr, hlstr
+from rpython.rtyper.test.test_rdict import BaseTestRDict
def get_indexes(ll_d):
@@ -21,7 +23,7 @@
c += 1
return c
-
+
class TestRDictDirect(object):
dummykeyobj = None
dummyvalueobj = None
@@ -252,3 +254,24 @@
class TestRDictDirectDummyValue(TestRDictDirect):
class dummyvalueobj:
ll_dummy_value = -42
+
+class TestOrderedRDict(BaseTestRDict):
+ @staticmethod
+ def newdict():
+ return OrderedDict()
+
+ def test_two_dicts_with_different_value_types(self):
+ def func(i):
+ d1 = OrderedDict()
+ d1['hello'] = i + 1
+ d2 = OrderedDict()
+ d2['world'] = d1
+ return d2['world']['hello']
+ res = self.interpret(func, [5])
+ assert res == 6
+
+ def test_dict_with_SHORT_keys(self):
+ py.test.skip("I don't want to edit this file on two branches")
+
+ def test_memoryerror_should_not_insert(self):
+ py.test.skip("I don't want to edit this file on two branches")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit