| # Copyright 2019 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| import sys |
| |
| # TODO(crbug.com/1174969): Remove this once Python2 is obsoleted. |
| if sys.version_info.major != 2: |
| long = int |
| basestring = str |
| |
| |
| def make_copy(obj, memo=None): |
| """ |
| Creates a copy of the given object, which should be an IR or part of IR. |
| |
| The copy is created basically as a deep copy of the object, but |make_copy| |
| method is used to create a (part of) copy if the object (or part of it) has |
| the method. |memo| argument behaves as the same as |deepcopy|. |
| """ |
| |
| if memo is None: |
| memo = dict() |
| |
| if (obj is None |
| or isinstance(obj, (bool, int, long, float, complex, basestring))): |
| # Do not make a copy if the object is of an immutable primitive type |
| # (or its subclass). |
| # |
| # Memoization is tricky in case that both of Identifier('x') and |
| # Component('x') exist. We could memoize them as |
| # |memo[(type(obj), obj)] = copy|, though. |
| return obj |
| |
| if hasattr(obj, 'make_copy'): |
| return obj.make_copy(memo=memo) |
| |
| memoizable = obj.__hash__ is not None |
| |
| if memoizable: |
| copy = memo.get(obj, None) |
| if copy is not None: |
| return copy |
| |
| def memoize(copy): |
| if memoizable: |
| memo[obj] = copy |
| return copy |
| |
| cls = type(obj) |
| |
| if isinstance(obj, (list, tuple, set, frozenset)): |
| return memoize(cls(map(lambda x: make_copy(x, memo), obj))) |
| |
| if isinstance(obj, dict): |
| return memoize( |
| cls([(make_copy(key, memo), make_copy(value, memo)) |
| for key, value in obj.items()])) |
| |
| if hasattr(obj, '__dict__'): |
| copy = memoize(cls.__new__(cls)) |
| for name, value in obj.__dict__.items(): |
| setattr(copy, name, make_copy(value, memo)) |
| return copy |
| |
| assert False, 'Unsupported type of object: {}'.format(cls) |