More protocol 2: TUPLE1, TUPLE2, TUPLE3.
Also moved the special case for empty tuples from save() to save_tuple().
This commit is contained in:
parent
9d32bb1708
commit
44f0ea5f73
|
@ -150,6 +150,8 @@ NEWFALSE = '\x89' # push False
|
||||||
LONG1 = '\x8a' # push long from < 256 bytes
|
LONG1 = '\x8a' # push long from < 256 bytes
|
||||||
LONG4 = '\x8b' # push really big long
|
LONG4 = '\x8b' # push really big long
|
||||||
|
|
||||||
|
_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]
|
||||||
|
|
||||||
|
|
||||||
__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)])
|
__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)])
|
||||||
del x
|
del x
|
||||||
|
@ -257,14 +259,6 @@ class Pickler:
|
||||||
|
|
||||||
t = type(object)
|
t = type(object)
|
||||||
|
|
||||||
# XXX Why are tuples a special case here?
|
|
||||||
if (t is TupleType) and (len(object) == 0):
|
|
||||||
if self.bin:
|
|
||||||
self.save_empty_tuple(object)
|
|
||||||
else:
|
|
||||||
self.save_tuple(object)
|
|
||||||
return
|
|
||||||
|
|
||||||
if d in memo:
|
if d in memo:
|
||||||
self.write(self.get(memo[d][0]))
|
self.write(self.get(memo[d][0]))
|
||||||
return
|
return
|
||||||
|
@ -463,6 +457,24 @@ class Pickler:
|
||||||
write = self.write
|
write = self.write
|
||||||
save = self.save
|
save = self.save
|
||||||
memo = self.memo
|
memo = self.memo
|
||||||
|
proto = self.proto
|
||||||
|
|
||||||
|
if proto >= 1:
|
||||||
|
n = len(object)
|
||||||
|
if n <= 3:
|
||||||
|
if not object:
|
||||||
|
write(EMPTY_TUPLE)
|
||||||
|
return
|
||||||
|
if proto >= 2:
|
||||||
|
for element in object:
|
||||||
|
save(element)
|
||||||
|
# Subtle. Same as in the big comment below
|
||||||
|
if id(object) in memo:
|
||||||
|
get = self.get(memo[id(object)][0])
|
||||||
|
write(POP_MARK + get)
|
||||||
|
else:
|
||||||
|
write(_tuplesize2code[n])
|
||||||
|
return
|
||||||
|
|
||||||
write(MARK)
|
write(MARK)
|
||||||
for element in object:
|
for element in object:
|
||||||
|
@ -477,15 +489,15 @@ class Pickler:
|
||||||
# could have been done in the "for element" loop instead, but
|
# could have been done in the "for element" loop instead, but
|
||||||
# recursive tuples are a rare thing.
|
# recursive tuples are a rare thing.
|
||||||
get = self.get(memo[id(object)][0])
|
get = self.get(memo[id(object)][0])
|
||||||
if self.bin:
|
if proto:
|
||||||
write(POP_MARK + get)
|
write(POP_MARK + get)
|
||||||
else: # proto 0 -- POP_MARK not available
|
else: # proto 0 -- POP_MARK not available
|
||||||
write(POP * (len(object) + 1) + get)
|
write(POP * (len(object) + 1) + get)
|
||||||
return
|
return
|
||||||
|
|
||||||
# No recursion (including the empty-tuple case).
|
# No recursion (including the empty-tuple case for protocol 0).
|
||||||
self.write(TUPLE)
|
self.write(TUPLE)
|
||||||
self.memoize(object)
|
self.memoize(object) # XXX shouldn't memoize empty tuple?!
|
||||||
|
|
||||||
dispatch[TupleType] = save_tuple
|
dispatch[TupleType] = save_tuple
|
||||||
|
|
||||||
|
@ -876,6 +888,18 @@ class Unpickler:
|
||||||
self.stack.append(())
|
self.stack.append(())
|
||||||
dispatch[EMPTY_TUPLE] = load_empty_tuple
|
dispatch[EMPTY_TUPLE] = load_empty_tuple
|
||||||
|
|
||||||
|
def load_tuple1(self):
|
||||||
|
self.stack[-1] = (self.stack[-1],)
|
||||||
|
dispatch[TUPLE1] = load_tuple1
|
||||||
|
|
||||||
|
def load_tuple2(self):
|
||||||
|
self.stack[-2:] = [(self.stack[-2], self.stack[-1])]
|
||||||
|
dispatch[TUPLE2] = load_tuple2
|
||||||
|
|
||||||
|
def load_tuple3(self):
|
||||||
|
self.stack[-3:] = [(self.stack[-3], self.stack[-2], self.stack[-1])]
|
||||||
|
dispatch[TUPLE3] = load_tuple3
|
||||||
|
|
||||||
def load_empty_list(self):
|
def load_empty_list(self):
|
||||||
self.stack.append([])
|
self.stack.append([])
|
||||||
dispatch[EMPTY_LIST] = load_empty_list
|
dispatch[EMPTY_LIST] = load_empty_list
|
||||||
|
|
|
@ -281,6 +281,18 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
y = self.loads(s)
|
y = self.loads(s)
|
||||||
self.assertEqual(x, y)
|
self.assertEqual(x, y)
|
||||||
|
|
||||||
|
def test_short_tuples(self):
|
||||||
|
a = ()
|
||||||
|
b = (12,)
|
||||||
|
c = (6, 6)
|
||||||
|
d = (4, 4, 4)
|
||||||
|
e = (3, 3, 3, 3)
|
||||||
|
for proto in 0, 1, 2:
|
||||||
|
for x in a, b, c, d, e:
|
||||||
|
s = self.dumps(x, proto)
|
||||||
|
y = self.loads(s)
|
||||||
|
self.assertEqual(x, y, (proto, x, s, y))
|
||||||
|
|
||||||
class AbstractPickleModuleTests(unittest.TestCase):
|
class AbstractPickleModuleTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_dump_closed_file(self):
|
def test_dump_closed_file(self):
|
||||||
|
|
Loading…
Reference in New Issue