mirror of
https://github.com/abakh/nbsdgames
synced 2025-04-28 14:09:32 -04:00
136 lines
3.7 KiB
Python
136 lines
3.7 KiB
Python
"""
|
|
A pure Python implementation of statesaver.c that runs on top of PyPy.
|
|
See description in statesaver.c.
|
|
Difference: this supports new-style instances too.
|
|
Use statesaver.standard_build() as the inst_build() if you want.
|
|
"""
|
|
|
|
from _pickle_support import generator_new
|
|
import types
|
|
|
|
def standard_build(self):
|
|
if type(self) is types.InstanceType:
|
|
# old-style instance
|
|
return types.InstanceType(self.__class__)
|
|
else:
|
|
# new-style instance
|
|
return type(self).__new__(type(self))
|
|
|
|
# ____________________________________________________________
|
|
|
|
def not_copied(x, memo):
|
|
return x
|
|
|
|
def copy_custom_instance(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
y = x.inst_build()
|
|
memo[id(x)] = y
|
|
for key, value in list(x.__dict__.items()):
|
|
y.__dict__[key] = copyrec(value, memo)
|
|
return y
|
|
|
|
def copy_tuple(x, memo):
|
|
return tuple([copyrec(item, memo) for item in x])
|
|
|
|
def copy_list(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
y = []
|
|
memo[id(x)] = y
|
|
for item in x:
|
|
y.append(copyrec(item, memo))
|
|
return y
|
|
|
|
def copy_dict(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
y = {}
|
|
memo[id(x)] = y
|
|
for key, value in list(x.items()):
|
|
y[copyrec(key, memo)] = copyrec(value, memo)
|
|
return y
|
|
|
|
def copy_function(x, memo):
|
|
if not x.__defaults__:
|
|
return x # not copied
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
y = types.FunctionType(x.__code__, x.__globals__, x.__name__)
|
|
memo[id(x)] = y
|
|
y.__defaults__ = copyrec(x.__defaults__, memo)
|
|
return y
|
|
|
|
def copy_method(x, memo):
|
|
return types.MethodType(copyrec(x.__func__, memo),
|
|
copyrec(x.__self__, memo),
|
|
x.__self__.__class__)
|
|
|
|
def copy_generator(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
y = generator_new(copyrec(x.gi_frame, memo), x.gi_running)
|
|
memo[id(x)] = y
|
|
return y
|
|
|
|
def copy_frame(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
frame_new, args, state = x.__reduce__()
|
|
y = frame_new(*args)
|
|
memo[id(x)] = y
|
|
newstate = []
|
|
for item in state:
|
|
if not (item is x.f_globals or item is x.f_builtins):
|
|
item = copyrec(item, memo)
|
|
newstate.append(item)
|
|
y.__setstate__(newstate)
|
|
return y
|
|
|
|
def copy_seqiter(x, memo):
|
|
try:
|
|
return memo[id(x)]
|
|
except KeyError:
|
|
# XXX self-recursion is not correctly handled here
|
|
seqiter_new, args = x.__reduce__()
|
|
args = [copyrec(item, memo) for item in args]
|
|
y = seqiter_new(*args)
|
|
memo[id(x)] = y
|
|
return y
|
|
|
|
# ____________________________________________________________
|
|
|
|
type_handlers = {tuple: copy_tuple,
|
|
list: copy_list,
|
|
dict: copy_dict,
|
|
types.FunctionType: copy_function,
|
|
types.MethodType: copy_method,
|
|
types.GeneratorType: copy_generator,
|
|
types.FrameType: copy_frame,
|
|
type(iter([])): copy_seqiter,
|
|
}
|
|
|
|
def no_handler_found(x, memo):
|
|
if hasattr(x, '__dict__') and hasattr(x.__class__, 'inst_build'):
|
|
handler = copy_custom_instance
|
|
else:
|
|
handler = not_copied
|
|
type_handlers[x.__class__] = handler
|
|
return handler(x, memo)
|
|
|
|
def copyrec(x, memo):
|
|
try:
|
|
cls = x.__class__
|
|
except AttributeError:
|
|
return x # 'cls' is likely an old-style class object
|
|
return type_handlers.get(cls, no_handler_found)(x, memo)
|
|
|
|
def copy(x):
|
|
return copyrec(x, {})
|