1.1 --- a/lib/__builtins__/sequence.py Wed Jan 11 12:26:04 2017 +0100
1.2 +++ b/lib/__builtins__/sequence.py Wed Jan 11 17:22:32 2017 +0100
1.3 @@ -19,6 +19,7 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 +from __builtins__.int import maxint
1.8 from native import isinstance as _isinstance
1.9
1.10 class itemaccess:
1.11 @@ -156,6 +157,30 @@
1.12
1.13 return 0
1.14
1.15 +class hashable(itemaccess):
1.16 +
1.17 + "An abstract class providing support for hashable sequences."
1.18 +
1.19 + _p = maxint / 32
1.20 + _a = 31
1.21 +
1.22 + def _hashvalue(self, fn):
1.23 +
1.24 + """
1.25 + Return a value for hashing purposes for the sequence using the given
1.26 + 'fn' on each item.
1.27 + """
1.28 +
1.29 + result = 0
1.30 + l = self.__len__()
1.31 + i = 0
1.32 +
1.33 + while i < l:
1.34 + result = (result * self._a + fn(self.__get_single_item__(i))) % self._p
1.35 + i += 1
1.36 +
1.37 + return result
1.38 +
1.39 class sequence(itemaccess):
1.40
1.41 "A common base class for sequence types."
1.42 @@ -214,6 +239,18 @@
1.43
1.44 "Return whether this sequence is equal to 'other'."
1.45
1.46 + try:
1.47 + return self._eq(other)
1.48 + except TypeError:
1.49 + return NotImplemented
1.50 +
1.51 + def _eq(self, other):
1.52 +
1.53 + """
1.54 + Return whether this sequence is equal to 'other' sequence. Note that
1.55 + this method will raise a TypeError if 'other' is not a sequence.
1.56 + """
1.57 +
1.58 # Sequences must have equal lengths to be equal.
1.59
1.60 n = self.__len__()
2.1 --- a/lib/__builtins__/str.py Wed Jan 11 12:26:04 2017 +0100
2.2 +++ b/lib/__builtins__/str.py Wed Jan 11 17:22:32 2017 +0100
2.3 @@ -19,20 +19,16 @@
2.4 this program. If not, see <http://www.gnu.org/licenses/>.
2.5 """
2.6
2.7 -from __builtins__.int import maxint
2.8 from __builtins__.operator import _negate
2.9 -from __builtins__.sequence import itemaccess
2.10 +from __builtins__.sequence import hashable, itemaccess
2.11 from __builtins__.types import check_int
2.12 from native import str_add, str_lt, str_gt, str_eq, str_len, str_nonempty, \
2.13 str_substr
2.14
2.15 -class basestring(itemaccess):
2.16 +class basestring(hashable):
2.17
2.18 "The base class for all strings."
2.19
2.20 - _p = maxint / 32
2.21 - _a = 31
2.22 -
2.23 def __init__(self, other=None):
2.24
2.25 "Initialise the string, perhaps from 'other'."
2.26 @@ -62,15 +58,7 @@
2.27
2.28 "Return a value for hashing purposes."
2.29
2.30 - result = 0
2.31 - l = self.__len__()
2.32 - i = 0
2.33 -
2.34 - while i < l:
2.35 - result = (result * self._a + ord(self.__get_single_item__(i))) % self._p
2.36 - i += 1
2.37 -
2.38 - return result
2.39 + return self._hashvalue(ord)
2.40
2.41 def _binary_op(self, op, other):
2.42
3.1 --- a/lib/__builtins__/tuple.py Wed Jan 11 12:26:04 2017 +0100
3.2 +++ b/lib/__builtins__/tuple.py Wed Jan 11 17:22:32 2017 +0100
3.3 @@ -20,11 +20,11 @@
3.4 """
3.5
3.6 from __builtins__.iterator import itemiterator
3.7 -from __builtins__.sequence import sequence
3.8 +from __builtins__.sequence import hashable, sequence
3.9 from native import list_element, list_init, list_len, list_setsize, \
3.10 list_setelement
3.11
3.12 -class tuple(sequence):
3.13 +class tuple(sequence, hashable):
3.14
3.15 "Implementation of tuple."
3.16
3.17 @@ -47,6 +47,12 @@
3.18 list_setelement(self.__data__, i, arg)
3.19 i += 1
3.20
3.21 + def __hash__(self):
3.22 +
3.23 + "Return a hashable value for the tuple."
3.24 +
3.25 + return self._hashvalue(hash)
3.26 +
3.27 def __getslice__(self, start, end=None):
3.28
3.29 "Return a slice starting from 'start', with the optional 'end'."
4.1 --- a/tests/dict.py Wed Jan 11 12:26:04 2017 +0100
4.2 +++ b/tests/dict.py Wed Jan 11 17:22:32 2017 +0100
4.3 @@ -5,37 +5,56 @@
4.4 for key, value in d.items():
4.5 return value
4.6
4.7 -d = {10 : "a", 20 : "b", "c" : 30}
4.8 +d = {10 : "a", 20 : "b", "c" : 30, (1, 2) : "d"}
4.9 +print "# d: ",
4.10 print d
4.11 print d[10] # a
4.12 print d[20] # b
4.13 print d["c"] # 30
4.14 +print d[(1, 2)] # d
4.15 try:
4.16 print d[30] # should fail with an exception
4.17 except KeyError, exc:
4.18 print "d[30]: key not found", exc.key
4.19
4.20 l = f(d)
4.21 +print "# l: ",
4.22 print l
4.23 print 10 in l # True
4.24 print 20 in l # True
4.25 print "c" in l # True
4.26 +print "d" in l # False
4.27 print 30 in l # False
4.28 +print (1, 2) in l # True
4.29
4.30 l = d.values()
4.31 +print "# l: ",
4.32 print l
4.33 print "a" in l # True
4.34 print "b" in l # True
4.35 +print "c" in l # False
4.36 +print "d" in l # True
4.37 print 30 in l # True
4.38 -print "c" in l # False
4.39 +print (1, 2) in l # False
4.40
4.41 -v = g(d) # either "a" or "b" or 30
4.42 +v = g(d) # either "a" or "b" or 30 or "d"
4.43 +print "# v: ",
4.44 print v
4.45 -print v == "a" or v == "b" or v == 30 # True
4.46 -print v == 10 or v == 20 or v == "c" # False
4.47 +print v == "a" or v == "b" or v == 30 or v == "d" # True
4.48 +print v == 10 or v == 20 or v == "c" or v == (1, 2) # False
4.49
4.50 l = d.items()
4.51 +print "# l: ",
4.52 print l
4.53 print (10, "a") in l # True
4.54 print ("c", 30) in l # True
4.55 +print ((1, 2), "d") in l # True
4.56 print (10, "b") in l # False
4.57 +
4.58 +# Try to put a list key in a dictionary.
4.59 +
4.60 +try:
4.61 + d[[1, 2]] = "e"
4.62 + print d[[1, 2]]
4.63 +except TypeError:
4.64 + print "d[[1, 2]]: key not appropriate"