Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / copy.py
CommitLineData
920dae64
AT
1"""Generic (shallow and deep) copying operations.
2
3Interface summary:
4
5 import copy
6
7 x = copy.copy(y) # make a shallow copy of y
8 x = copy.deepcopy(y) # make a deep copy of y
9
10For module specific errors, copy.Error is raised.
11
12The difference between shallow and deep copying is only relevant for
13compound objects (objects that contain other objects, like lists or
14class instances).
15
16- A shallow copy constructs a new compound object and then (to the
17 extent possible) inserts *the same objects* into it that the
18 original contains.
19
20- A deep copy constructs a new compound object and then, recursively,
21 inserts *copies* into it of the objects found in the original.
22
23Two problems often exist with deep copy operations that don't exist
24with shallow copy operations:
25
26 a) recursive objects (compound objects that, directly or indirectly,
27 contain a reference to themselves) may cause a recursive loop
28
29 b) because deep copy copies *everything* it may copy too much, e.g.
30 administrative data structures that should be shared even between
31 copies
32
33Python's deep copy operation avoids these problems by:
34
35 a) keeping a table of objects already copied during the current
36 copying pass
37
38 b) letting user-defined classes override the copying operation or the
39 set of components copied
40
41This version does not copy types like module, class, function, method,
42nor stack trace, stack frame, nor file, socket, window, nor array, nor
43any similar types.
44
45Classes can use the same interfaces to control copying that they use
46to control pickling: they can define methods called __getinitargs__(),
47__getstate__() and __setstate__(). See the documentation for module
48"pickle" for information on these methods.
49"""
50
51import types
52from copy_reg import dispatch_table
53
54class Error(Exception):
55 pass
56error = Error # backward compatibility
57
58try:
59 from org.python.core import PyStringMap
60except ImportError:
61 PyStringMap = None
62
63__all__ = ["Error", "copy", "deepcopy"]
64
65import inspect
66def _getspecial(cls, name):
67 for basecls in inspect.getmro(cls):
68 try:
69 return basecls.__dict__[name]
70 except:
71 pass
72 else:
73 return None
74
75def copy(x):
76 """Shallow copy operation on arbitrary Python objects.
77
78 See the module's __doc__ string for more info.
79 """
80
81 cls = type(x)
82
83 copier = _copy_dispatch.get(cls)
84 if copier:
85 return copier(x)
86
87 copier = _getspecial(cls, "__copy__")
88 if copier:
89 return copier(x)
90
91 reductor = dispatch_table.get(cls)
92 if reductor:
93 rv = reductor(x)
94 else:
95 reductor = getattr(x, "__reduce_ex__", None)
96 if reductor:
97 rv = reductor(2)
98 else:
99 reductor = getattr(x, "__reduce__", None)
100 if reductor:
101 rv = reductor()
102 else:
103 copier = getattr(x, "__copy__", None)
104 if copier:
105 return copier()
106 raise Error("un(shallow)copyable object of type %s" % cls)
107
108 return _reconstruct(x, rv, 0)
109
110
111_copy_dispatch = d = {}
112
113def _copy_immutable(x):
114 return x
115for t in (types.NoneType, int, long, float, bool, str, tuple,
116 frozenset, type, xrange, types.ClassType,
117 types.BuiltinFunctionType):
118 d[t] = _copy_immutable
119for name in ("ComplexType", "UnicodeType", "CodeType"):
120 t = getattr(types, name, None)
121 if t is not None:
122 d[t] = _copy_immutable
123
124def _copy_with_constructor(x):
125 return type(x)(x)
126for t in (list, dict, set):
127 d[t] = _copy_with_constructor
128
129def _copy_with_copy_method(x):
130 return x.copy()
131if PyStringMap is not None:
132 d[PyStringMap] = _copy_with_copy_method
133
134def _copy_inst(x):
135 if hasattr(x, '__copy__'):
136 return x.__copy__()
137 if hasattr(x, '__getinitargs__'):
138 args = x.__getinitargs__()
139 y = x.__class__(*args)
140 else:
141 y = _EmptyClass()
142 y.__class__ = x.__class__
143 if hasattr(x, '__getstate__'):
144 state = x.__getstate__()
145 else:
146 state = x.__dict__
147 if hasattr(y, '__setstate__'):
148 y.__setstate__(state)
149 else:
150 y.__dict__.update(state)
151 return y
152d[types.InstanceType] = _copy_inst
153
154del d
155
156def deepcopy(x, memo=None, _nil=[]):
157 """Deep copy operation on arbitrary Python objects.
158
159 See the module's __doc__ string for more info.
160 """
161
162 if memo is None:
163 memo = {}
164
165 d = id(x)
166 y = memo.get(d, _nil)
167 if y is not _nil:
168 return y
169
170 cls = type(x)
171
172 copier = _deepcopy_dispatch.get(cls)
173 if copier:
174 y = copier(x, memo)
175 else:
176 try:
177 issc = issubclass(cls, type)
178 except TypeError: # cls is not a class (old Boost; see SF #502085)
179 issc = 0
180 if issc:
181 y = _deepcopy_atomic(x, memo)
182 else:
183 copier = _getspecial(cls, "__deepcopy__")
184 if copier:
185 y = copier(x, memo)
186 else:
187 reductor = dispatch_table.get(cls)
188 if reductor:
189 rv = reductor(x)
190 else:
191 reductor = getattr(x, "__reduce_ex__", None)
192 if reductor:
193 rv = reductor(2)
194 else:
195 reductor = getattr(x, "__reduce__", None)
196 if reductor:
197 rv = reductor()
198 else:
199 copier = getattr(x, "__deepcopy__", None)
200 if copier:
201 return copier(memo)
202 raise Error(
203 "un(deep)copyable object of type %s" % cls)
204 y = _reconstruct(x, rv, 1, memo)
205
206 memo[d] = y
207 _keep_alive(x, memo) # Make sure x lives at least as long as d
208 return y
209
210_deepcopy_dispatch = d = {}
211
212def _deepcopy_atomic(x, memo):
213 return x
214d[types.NoneType] = _deepcopy_atomic
215d[types.IntType] = _deepcopy_atomic
216d[types.LongType] = _deepcopy_atomic
217d[types.FloatType] = _deepcopy_atomic
218d[types.BooleanType] = _deepcopy_atomic
219try:
220 d[types.ComplexType] = _deepcopy_atomic
221except AttributeError:
222 pass
223d[types.StringType] = _deepcopy_atomic
224try:
225 d[types.UnicodeType] = _deepcopy_atomic
226except AttributeError:
227 pass
228try:
229 d[types.CodeType] = _deepcopy_atomic
230except AttributeError:
231 pass
232d[types.TypeType] = _deepcopy_atomic
233d[types.XRangeType] = _deepcopy_atomic
234d[types.ClassType] = _deepcopy_atomic
235d[types.BuiltinFunctionType] = _deepcopy_atomic
236
237def _deepcopy_list(x, memo):
238 y = []
239 memo[id(x)] = y
240 for a in x:
241 y.append(deepcopy(a, memo))
242 return y
243d[types.ListType] = _deepcopy_list
244
245def _deepcopy_tuple(x, memo):
246 y = []
247 for a in x:
248 y.append(deepcopy(a, memo))
249 d = id(x)
250 try:
251 return memo[d]
252 except KeyError:
253 pass
254 for i in range(len(x)):
255 if x[i] is not y[i]:
256 y = tuple(y)
257 break
258 else:
259 y = x
260 memo[d] = y
261 return y
262d[types.TupleType] = _deepcopy_tuple
263
264def _deepcopy_dict(x, memo):
265 y = {}
266 memo[id(x)] = y
267 for key, value in x.iteritems():
268 y[deepcopy(key, memo)] = deepcopy(value, memo)
269 return y
270d[types.DictionaryType] = _deepcopy_dict
271if PyStringMap is not None:
272 d[PyStringMap] = _deepcopy_dict
273
274def _keep_alive(x, memo):
275 """Keeps a reference to the object x in the memo.
276
277 Because we remember objects by their id, we have
278 to assure that possibly temporary objects are kept
279 alive by referencing them.
280 We store a reference at the id of the memo, which should
281 normally not be used unless someone tries to deepcopy
282 the memo itself...
283 """
284 try:
285 memo[id(memo)].append(x)
286 except KeyError:
287 # aha, this is the first one :-)
288 memo[id(memo)]=[x]
289
290def _deepcopy_inst(x, memo):
291 if hasattr(x, '__deepcopy__'):
292 return x.__deepcopy__(memo)
293 if hasattr(x, '__getinitargs__'):
294 args = x.__getinitargs__()
295 args = deepcopy(args, memo)
296 y = x.__class__(*args)
297 else:
298 y = _EmptyClass()
299 y.__class__ = x.__class__
300 memo[id(x)] = y
301 if hasattr(x, '__getstate__'):
302 state = x.__getstate__()
303 else:
304 state = x.__dict__
305 state = deepcopy(state, memo)
306 if hasattr(y, '__setstate__'):
307 y.__setstate__(state)
308 else:
309 y.__dict__.update(state)
310 return y
311d[types.InstanceType] = _deepcopy_inst
312
313def _reconstruct(x, info, deep, memo=None):
314 if isinstance(info, str):
315 return x
316 assert isinstance(info, tuple)
317 if memo is None:
318 memo = {}
319 n = len(info)
320 assert n in (2, 3, 4, 5)
321 callable, args = info[:2]
322 if n > 2:
323 state = info[2]
324 else:
325 state = {}
326 if n > 3:
327 listiter = info[3]
328 else:
329 listiter = None
330 if n > 4:
331 dictiter = info[4]
332 else:
333 dictiter = None
334 if deep:
335 args = deepcopy(args, memo)
336 y = callable(*args)
337 memo[id(x)] = y
338 if listiter is not None:
339 for item in listiter:
340 if deep:
341 item = deepcopy(item, memo)
342 y.append(item)
343 if dictiter is not None:
344 for key, value in dictiter:
345 if deep:
346 key = deepcopy(key, memo)
347 value = deepcopy(value, memo)
348 y[key] = value
349 if state:
350 if deep:
351 state = deepcopy(state, memo)
352 if hasattr(y, '__setstate__'):
353 y.__setstate__(state)
354 else:
355 if isinstance(state, tuple) and len(state) == 2:
356 state, slotstate = state
357 else:
358 slotstate = None
359 if state is not None:
360 y.__dict__.update(state)
361 if slotstate is not None:
362 for key, value in slotstate.iteritems():
363 setattr(y, key, value)
364 return y
365
366del d
367
368del types
369
370# Helper for instance creation without calling __init__
371class _EmptyClass:
372 pass
373
374def _test():
375 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
376 {'abc': 'ABC'}, (), [], {}]
377 l1 = copy(l)
378 print l1==l
379 l1 = map(copy, l)
380 print l1==l
381 l1 = deepcopy(l)
382 print l1==l
383 class C:
384 def __init__(self, arg=None):
385 self.a = 1
386 self.arg = arg
387 if __name__ == '__main__':
388 import sys
389 file = sys.argv[0]
390 else:
391 file = __file__
392 self.fp = open(file)
393 self.fp.close()
394 def __getstate__(self):
395 return {'a': self.a, 'arg': self.arg}
396 def __setstate__(self, state):
397 for key, value in state.iteritems():
398 setattr(self, key, value)
399 def __deepcopy__(self, memo=None):
400 new = self.__class__(deepcopy(self.arg, memo))
401 new.a = self.a
402 return new
403 c = C('argument sketch')
404 l.append(c)
405 l2 = copy(l)
406 print l == l2
407 print l
408 print l2
409 l2 = deepcopy(l)
410 print l == l2
411 print l
412 print l2
413 l.append({l[1]: l, 'xyz': l[2]})
414 l3 = copy(l)
415 import repr
416 print map(repr.repr, l)
417 print map(repr.repr, l1)
418 print map(repr.repr, l2)
419 print map(repr.repr, l3)
420 l3 = deepcopy(l)
421 import repr
422 print map(repr.repr, l)
423 print map(repr.repr, l1)
424 print map(repr.repr, l2)
425 print map(repr.repr, l3)
426
427if __name__ == '__main__':
428 _test()