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): ...@@ -58,17 +58,21 @@ class ExtendedAttribute(object):
self._format = self._FORM_IDENT_LIST self._format = self._FORM_IDENT_LIST
self._values = tuple(values) self._values = tuple(values)
def __eq__(self, other): @classmethod
if not isinstance(other, self.__class__): def equals(cls, lhs, rhs):
return NotImplemented """
return (self.key == other.key Returns True if |lhs| and |rhs| have the same contents.
and self.syntactic_form == other.syntactic_form)
def __ne__(self, other): Note that |lhs == rhs| evaluates to True if lhs and rhs are the same
return not self == other 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 (lhs.key == rhs.key
return hash((self._key, self._values, self._arguments)) and lhs.syntactic_form == rhs.syntactic_form)
@property @property
def syntactic_form(self): def syntactic_form(self):
...@@ -171,23 +175,28 @@ class ExtendedAttributes(object): ...@@ -171,23 +175,28 @@ class ExtendedAttributes(object):
self._keys = tuple(sorted(self._ext_attrs.keys())) self._keys = tuple(sorted(self._ext_attrs.keys()))
self._length = len(sorted_ext_attrs) self._length = len(sorted_ext_attrs)
def __eq__(self, other): @classmethod
if not isinstance(other, self.__class__): def equals(cls, lhs, rhs):
return NotImplemented """
if self.keys() != other.keys(): 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 return False
if len(self) != len(other): if len(lhs) != len(rhs):
return False return False
for lhs, rhs in zip(self, other): for l, r in zip(lhs, rhs):
if lhs != rhs: if not ExtendedAttribute.equals(l, r):
return False return False
return True return True
def __ne__(self, other):
return not self == other
__hash__ = None
def __contains__(self, key): def __contains__(self, key):
"""Returns True if this has an extended attribute with the |key|.""" """Returns True if this has an extended attribute with the |key|."""
return key in self._ext_attrs return key in self._ext_attrs
......
...@@ -11,6 +11,7 @@ from .composition_parts import WithCodeGeneratorInfo ...@@ -11,6 +11,7 @@ from .composition_parts import WithCodeGeneratorInfo
from .composition_parts import WithDebugInfo from .composition_parts import WithDebugInfo
from .composition_parts import WithExtendedAttributes from .composition_parts import WithExtendedAttributes
from .composition_parts import WithIdentifier from .composition_parts import WithIdentifier
from .extended_attribute import ExtendedAttributes
from .reference import Proxy from .reference import Proxy
from .reference import RefById from .reference import RefById
from .typedef import Typedef from .typedef import Typedef
...@@ -140,8 +141,10 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo): ...@@ -140,8 +141,10 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo):
self._is_optional = is_optional self._is_optional = is_optional
def __eq__(self, other): def __eq__(self, other):
"""Returns True if |self| and |other| represent the equivalent type."""
return (self.__class__ == other.__class__ 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) and self.is_optional == other.is_optional)
def __ne__(self, other): def __ne__(self, other):
...@@ -150,7 +153,7 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo): ...@@ -150,7 +153,7 @@ class IdlType(WithExtendedAttributes, WithCodeGeneratorInfo, WithDebugInfo):
def __hash__(self): def __hash__(self):
raise exceptions.NotImplementedError() raise exceptions.NotImplementedError()
def make_copy(self): def make_copy(self, memo):
return self return self
@property @property
......
...@@ -3,40 +3,48 @@ ...@@ -3,40 +3,48 @@
# found in the LICENSE file. # 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. 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| 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 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): if memo is None:
return class_.__new__(class_, *args) memo = dict()
if obj is None: if obj is None:
return None return None
if hasattr(obj, 'make_copy'): 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)): if isinstance(obj, (bool, int, long, float, complex, basestring)):
# Subclasses of simple builtin types are expected to have a copy # Subclasses of simple builtin types are expected to have a copy
# constructor. # constructor.
return construct(type(obj), obj) return cls.__new__(cls, obj)
if isinstance(obj, (list, tuple, set, frozenset)): 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): if isinstance(obj, dict):
return type(obj)([(make_copy(key), make_copy(value)) return cls([(make_copy(key, memo), make_copy(value, memo))
for key, value in obj.iteritems()]) for key, value in obj.iteritems()])
if hasattr(obj, '__dict__'): if hasattr(obj, '__dict__'):
copy = construct(type(obj)) copy = cls.__new__(cls)
memo[obj] = copy
for name, value in obj.__dict__.iteritems(): for name, value in obj.__dict__.iteritems():
setattr(copy, name, make_copy(value)) setattr(copy, name, make_copy(value, memo))
return copy 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): ...@@ -86,7 +86,7 @@ class Proxy(object):
if not attr.startswith('_') if not attr.startswith('_')
]) ])
def make_copy(self): def make_copy(self, memo):
return self return self
def set_target_object(self, target_object): def set_target_object(self, target_object):
......
...@@ -103,7 +103,7 @@ class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent, ...@@ -103,7 +103,7 @@ class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
@property @property
def does_include_nullable_type(self): 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. includes a nullable type.
""" """
return self._does_include_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