chromium/third_party/blink/renderer/bindings/scripts/web_idl/make_copy.py

# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.


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, float, complex, str)):
        # 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)