Skip to content

Commit

Permalink
Merge pull request #59 from praetorian20/perf_improvements
Browse files Browse the repository at this point in the history
Performance improvements - cache attributes and avoid runtime checks (#56)
  • Loading branch information
iMichka committed Jul 5, 2016
2 parents 0f467ae + 1e8878b commit 25bf2b2
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
38 changes: 25 additions & 13 deletions pygccxml/declarations/class_declaration.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,29 @@ def __init__(self, related_class=None, access=None, is_virtual=False):
assert(access in ACCESS_TYPES.ALL)
self._access = access
self._is_virtual = is_virtual
self._declaration_path = None
self._declaration_path_hash = None

def __eq__(self, other):
if not isinstance(other, hierarchy_info_t):
return False
return declaration_utils.declaration_path(self.related_class) == \
declaration_utils.declaration_path(other.related_class) \
and self.access == other.access \
and self.is_virtual == other.is_virtual
return (self.declaration_path_hash ==
other.declaration_path_hash) \
and self._declaration_path == other._declaration_path \
and self._access == other._access \
and self._is_virtual == other._is_virtual

def __hash__(self):
return hash(declaration_utils.declaration_path(self.related_class))
return self.declaration_path_hash

def __ne__(self, other):
return not self.__eq__(other)

def __lt__(self, other):
if not isinstance(other, self.__class__):
return self.__class__.__name__ < other.__class__.__name__
return (
declaration_utils.declaration_path(self.related_class),
self.access,
self.is_virtual) < (
declaration_utils.declaration_path(
other.related_class),
other.access,
self.is_virtual)
return (self.declaration_path, self.access, self.is_virtual) < \
(other.declaration_path, other.access, other.is_virtual)

@property
def related_class(self):
Expand All @@ -104,6 +101,8 @@ def related_class(self, new_related_class):
if new_related_class:
assert(isinstance(new_related_class, class_t))
self._related_class = new_related_class
self._declaration_path = None
self._declaration_path_hash = None

@property
def access(self):
Expand Down Expand Up @@ -135,6 +134,19 @@ def is_virtual(self):
def is_virtual(self, new_is_virtual):
self._is_virtual = new_is_virtual

@property
def declaration_path(self):
if self._declaration_path is None:
self._declaration_path = declaration_utils.declaration_path(
self.related_class)
return self._declaration_path

@property
def declaration_path_hash(self):
if self._declaration_path_hash is None:
self._declaration_path_hash = hash(tuple(self.declaration_path))
return self._declaration_path_hash


class class_declaration_t(declaration.declaration_t):

Expand Down
28 changes: 24 additions & 4 deletions pygccxml/parser/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ def __init__(self, xml_file, decl_factory, config, *args):
self.__mangled_suffix = ' *INTERNAL* '
self.__mangled_suffix_len = len(self.__mangled_suffix)

self.__name_attrs_to_skip = []
self.__read_location = \
lambda decl, attrs, to_skip: self.__read_location_bootstrap(
self, decl, attrs, to_skip)

def read(self):
xml.sax.parse(self.xml_file, self)

Expand Down Expand Up @@ -223,7 +228,7 @@ def startElement(self, name, attrs):
self.__update_membership(attrs)
self.__declarations[element_id] = obj
if not isinstance(obj, declarations.namespace_t):
self.__read_location(obj, attrs)
self.__read_location(obj, attrs, self.__name_attrs_to_skip)
if isinstance(obj, declarations.class_t):
self.__read_bases(obj, attrs)
if isinstance(obj, declarations.typedef_t):
Expand Down Expand Up @@ -260,16 +265,19 @@ def endElement(self, name):
self.__inst = None

@staticmethod
def __read_location(decl, attrs):
def __read_location_bootstrap(inst, decl, attrs, to_skip):
""" This function monkey patches the __read_location function to either
__read_location_gccxml or __read_location_castxml depending on the
xml generator in use
"""

to_skip = []
if "CastXML" in utils.xml_generator:
# These fields are generated by clang, and have no location.
# Just set an empty location for them. Gccxml does not have
# this problem.
# bug #19: gp_offset, fp_offset, overflow_arg_area, reg_save_area
# bug #32: isa, flags, str and length were added in llvm 3.9
to_skip = [
inst.__name_attrs_to_skip = [
"gp_offset",
"fp_offset",
"overflow_arg_area",
Expand All @@ -279,7 +287,19 @@ def __read_location(decl, attrs):
"str",
"length"
]
inst.__read_location = inst.__read_location_castxml
else:
inst.__read_location = inst.__read_location_gccxml
return inst.__read_location(decl, attrs, inst.__name_attrs_to_skip)

@staticmethod
def __read_location_gccxml(decl, attrs, to_skip):
decl.location = declarations.location_t(
file_name=attrs[XML_AN_FILE],
line=int(attrs[XML_AN_LINE]))

@staticmethod
def __read_location_castxml(decl, attrs, to_skip):
if "name" in attrs and attrs["name"] in to_skip:
decl.location = declarations.location_t('', -1)
else:
Expand Down

0 comments on commit 25bf2b2

Please sign in to comment.