Commit 45223332 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

IDL compiler: Make make_copy as if deepcopy

Makes make_copy makes a copy with the same structure as the
original object has.  Like |deepcopy| uses |memo| argument,
make_copy uses |memo| argument, too.

ExtendedAttribute(s)'s __eq__ are replaced with |equals|
class method so that __eq__ works on the object identity.
This is necessary to make |memo| above work.

Bug: 839389
Change-Id: I5896ef07787dd0086f510ae4102a5f538a9b5c56
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1765098Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690283}
parent b537294d
......@@ -58,17 +58,21 @@ class ExtendedAttribute(object):
self._format = self._FORM_IDENT_LIST
self._values = tuple(values)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.key == other.key
and self.syntactic_form == other.syntactic_form)
@classmethod
def equals(cls, lhs, rhs):
"""
Returns True if |lhs| and |rhs| have the same contents.
def __ne__(self, other):
return not self == other
Note that |lhs == rhs| evaluates to True if lhs and rhs are the same
object.
"""
if lhs is None and rhs is None:
return True
if not all(isinstance(x, cls) for x in (lhs, rhs)):
return False
def __hash__(self):
return hash((self._key, self._values, self._arguments))
return (lhs.key == rhs.key
and lhs.syntactic_form == rhs.syntactic_form)
@property
def syntactic_form(self):
......@@ -171,23 +175,28 @@ class ExtendedAttributes(object):
self._keys = tuple(sorted(self._ext_attrs.keys()))
self._length = len(sorted_ext_attrs)
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
if self.keys() != other.keys():
@classmethod
def equals(cls, lhs, rhs):
"""
Returns True if |lhs| and |rhs| have the same contents.
Note that |lhs == rhs| evaluates to True if lhs and rhs are the same
object.
"""
if lhs is None and rhs is None:
return True
if not all(isinstance(x, cls) for x in (lhs, rhs)):
return False
if lhs.keys() != rhs.keys():
return False
if len(self) != len(other):
if len(lhs) != len(rhs):
return False
for lhs, rhs in zip(self, other):
if lhs != rhs:
for l, r in zip(lhs, rhs):
if not ExtendedAttribute.equals(l, r):
return False
return True
def __ne__(self, other):
return not self == other
__hash__ = None
def __contains__(self, key):
"""Returns True if this has an extended attribute with the |key|."""
return key in self._ext_attrs
......
......@@ -11,6 +11,7 @@ from .composition_parts import WithCodeGeneratorInfo
from .composition_parts import WithDebugInfo
from .composition_parts import WithExtendedAttributes
from .composition_parts import WithIdentifier
from .extended_attribute import ExtendedAttributes
from .reference import Proxy
from .reference import RefById
from .typedef import Typedef
......@@ -140,8 +141,10 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo):
self._is_optional = is_optional
def __eq__(self, other):
"""Returns True if |self| and |other| represent the equivalent type."""
return (self.__class__ == other.__class__
and self.extended_attributes == other.extended_attributes
and ExtendedAttributes.equals(self.extended_attributes,
other.extended_attributes)
and self.is_optional == other.is_optional)
def __ne__(self, other):
......@@ -150,7 +153,7 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo):
def __hash__(self):
raise exceptions.NotImplementedError()
def make_copy(self):
def make_copy(self, memo):
return self
@property
......
......@@ -3,40 +3,48 @@
# found in the LICENSE file.
def make_copy(obj):
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.
the method. |memo| argument behaves as the same as |deepcopy|.
"""
def construct(class_, *args):
return class_.__new__(class_, *args)
if memo is None:
memo = dict()
if obj is None:
return None
if hasattr(obj, 'make_copy'):
return obj.make_copy()
return obj.make_copy(memo=memo)
if obj.__hash__ is not None:
copy = memo.get(obj, None)
if copy is not None:
return copy
cls = type(obj)
if isinstance(obj, (bool, int, long, float, complex, basestring)):
# Subclasses of simple builtin types are expected to have a copy
# constructor.
return construct(type(obj), obj)
return cls.__new__(cls, obj)
if isinstance(obj, (list, tuple, set, frozenset)):
return type(obj)(map(make_copy, obj))
return cls(map(lambda x: make_copy(x, memo), obj))
if isinstance(obj, dict):
return type(obj)([(make_copy(key), make_copy(value))
for key, value in obj.iteritems()])
return cls([(make_copy(key, memo), make_copy(value, memo))
for key, value in obj.iteritems()])
if hasattr(obj, '__dict__'):
copy = construct(type(obj))
copy = cls.__new__(cls)
memo[obj] = copy
for name, value in obj.__dict__.iteritems():
setattr(copy, name, make_copy(value))
setattr(copy, name, make_copy(value, memo))
return copy
assert False, 'Unsupported type of object: {}'.format(type(obj))
assert False, 'Unsupported type of object: {}'.format(cls)
......@@ -86,7 +86,7 @@ class Proxy(object):
if not attr.startswith('_')
])
def make_copy(self):
def make_copy(self, memo):
return self
def set_target_object(self, target_object):
......
......@@ -103,7 +103,7 @@ class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
@property
def does_include_nullable_type(self):
"""
Returns true if any of member type is nullable or a member union
Returns True if any of member type is nullable or a member union
includes a nullable type.
"""
return self._does_include_nullable_type
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment