# HG changeset patch # User Paul Boddie # Date 1320084587 -3600 # Node ID a6ddb1e042ea1384adb2baf579a04d82c5804150 # Parent 7bc0a55652d132ae9f20e26f8f0c6ac584769c48 Switched the attribute usage empty set representation from a new ObjectSet instance to None, introducing logic to handle the addition of attribute usage observations to such empty sets and to detect empty sets when type deductions are being made. This reduces the amount of allocated instances enormously. Changed the combination function for mapping dictionaries (mapping from names to object sets) to not propagate observations for names to locations where such names are not defined. diff -r 7bc0a55652d1 -r a6ddb1e042ea internal_tests/objectset.py --- a/internal_tests/objectset.py Mon Oct 24 23:57:02 2011 +0200 +++ b/internal_tests/objectset.py Mon Oct 31 19:09:47 2011 +0100 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from micropython.common import ObjectSet +from micropython.common import ObjectSet, combine_mapping_dicts o1 = ObjectSet() o1.add("a") @@ -47,4 +47,16 @@ o3["c"].append("y") print "o3 =", o3 +d1 = {'a' : [ObjectSet(['f', 'g']), ObjectSet(['f', 'h'])]} +d2 = {'a' : [ObjectSet(['f']), ObjectSet(['e', 'f', 'g'])]} +d3 = combine_mapping_dicts(d1, d2) +print "d1 =", d1 +print "d2 =", d2 +print "d3 =", d3 + +d4 = {'a' : None} +d5 = combine_mapping_dicts(d1, d4) +print "d4 =", d4 +print "d5 =", d5 + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 7bc0a55652d1 -r a6ddb1e042ea micropython/common.py --- a/micropython/common.py Mon Oct 24 23:57:02 2011 +0200 +++ b/micropython/common.py Mon Oct 31 19:09:47 2011 +0100 @@ -128,7 +128,10 @@ new_dict = {} for key, value in d.items(): - new_dict[key] = set([value]) + if value is None: + new_dict[key] = None + else: + new_dict[key] = set([value]) return new_dict def merge_mapping_dicts(dicts): @@ -145,10 +148,11 @@ for old_dict in dicts: for key, value in old_dict.items(): - if not new_dict.has_key(key): - new_dict[key] = ObjectSet(value) - else: - new_dict[key].update(value) + if value is not None: + if not new_dict.has_key(key): + new_dict[key] = ObjectSet(value) + else: + new_dict[key].update(value) def combine_mapping_dicts(d1, d2): @@ -163,22 +167,31 @@ d1: {'a' : [{'f', 'g'}, {'f', 'h'}], ...} d2: {'a' : [{'f'}, {'e', 'f', 'g'}], ...} -> {'a' : [{'f', 'g'}, {'f', 'h'}, {'e', 'f', 'g'}, {'e', 'f', 'g', 'h'}], ...} + + Note that items of 'd2' whose keys are not in 'd1' are not added to 'd1' + since this, in the context of propagating attribute usage observations, + would result in spurious usage details being made available in places where + the names may not have been defined. """ - return combine(d1, d2, {}, combine_object_set_lists) + return combine(d1, d2, {}, combine_object_set_lists, True) -def combine(d1, d2, combined, combine_op): +def combine(d1, d2, combined, combine_op, only_d1_keys=False): """ Combine dictionaries 'd1' and 'd2' in the 'combined' object provided, using the 'combine_op' to merge values from the dictionaries. + + If 'only_d1_keys' is set to a true value, items from 'd2' employing keys not + in 'd1' will not be added to 'd1'. """ d2_keys = d2.keys() for key in d2_keys: if not d1.has_key(key): - combined[key] = d2[key] + if not only_d1_keys: + combined[key] = d2[key] else: combined[key] = combine_op(d1[key], d2[key]) @@ -195,6 +208,14 @@ members. """ + if l1 is None: + if l2 is None: + return None + else: + return l2 + elif l2 is None: + return l1 + combined = set([]) for i1 in l1: for i2 in l2: diff -r 7bc0a55652d1 -r a6ddb1e042ea micropython/data.py --- a/micropython/data.py Mon Oct 24 23:57:02 2011 +0200 +++ b/micropython/data.py Mon Oct 31 19:09:47 2011 +0100 @@ -404,10 +404,7 @@ # Skip reporting where no actual usage occurs. - for attrnames in usage: - if attrnames: - break - else: + if usage is None: continue # Eliminate non-usage. @@ -513,6 +510,8 @@ if users.has_key(name): for user in users[name]: values = user._attrnames[name] + if values is None: + values = user._attrnames[name] = ObjectSet() # Add an entry for the attribute, optionally with an assigned # value. @@ -558,7 +557,7 @@ "Make sure that 'node' is initialised for 'name'." self._init_attribute_user(node) - node._attrnames[name] = ObjectSet() + node._attrnames[name] = None def _init_attribute_user(self, node): @@ -1886,7 +1885,8 @@ for user in self.all_attribute_users: user._attrtypes = {} for name, usage in user._attrcombined.items(): - user._attrtypes[name] = get_object_types_for_usage(usage, objtable, name, self.full_name()) + if usage is not None: + user._attrtypes[name] = get_object_types_for_usage(usage, objtable, name, self.full_name()) def as_instantiator(self):