summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Binkert <binkertn@umich.edu>2005-03-22 00:53:01 -0500
committerNathan Binkert <binkertn@umich.edu>2005-03-22 00:53:01 -0500
commit3583fb6830285cf163d7b37cc6d0dd00cae7b1fa (patch)
tree09436aa8154b46b9f17a80391a48cc5d500281ee
parent62ce65c3784dfd5067e88adc51286960673c9000 (diff)
downloadgem5-3583fb6830285cf163d7b37cc6d0dd00cae7b1fa.tar.xz
Use the multidict in the python config stuff. Makes code a bit
cleaner. python/m5/config.py: Use the multidict instead of the separately coded _getparam and _getvalue stuff. While we're at it, when we see a default parameter, we stick it into the dictionary right away. --HG-- extra : convert_revision : d6f6f5cc454a479e27718ec7952cd7559229ebe7
-rw-r--r--python/m5/config.py176
-rw-r--r--python/m5/multidict.py158
2 files changed, 213 insertions, 121 deletions
diff --git a/python/m5/config.py b/python/m5/config.py
index 74490f473..68098bf14 100644
--- a/python/m5/config.py
+++ b/python/m5/config.py
@@ -29,6 +29,7 @@ import os, re, sys, types, inspect
from m5 import panic
from convert import *
+from multidict import multidict
noDot = False
try:
@@ -325,17 +326,22 @@ class MetaConfigNode(type):
super(MetaConfigNode, cls).__init__(name, bases, dict)
# initialize required attributes
- cls._params = {}
- cls._values = {}
+ cls._params = multidict()
+ cls._values = multidict()
cls._param_types = {}
cls._bases = [c for c in cls.__mro__ if isConfigNode(c)]
cls._anon_subclass_counter = 0
- # If your parent has a value in it that's a config node, clone
- # it. Do this now so if we update any of the values'
- # attributes we are updating the clone and not the original.
- for base in cls._bases:
- for key,val in base._values.iteritems():
+ # We don't support multiple inheritence. If you want to, you
+ # must fix multidict to deal with it properly.
+ sob = [ base for base in bases \
+ if issubclass(base, ParamType) and base != ParamType ]
+
+ if len(sob) == 1:
+ # If your parent has a value in it that's a config node, clone
+ # it. Do this now so if we update any of the values'
+ # attributes we are updating the clone and not the original.
+ for key,val in sob[0]._values.iteritems():
# don't clone if (1) we're about to overwrite it with
# a local setting or (2) we've already cloned a copy
@@ -345,12 +351,19 @@ class MetaConfigNode(type):
if isConfigNode(val):
cls._values[key] = val()
- elif isSimObjSequence(val):
+ elif isSimObjSequence(val) and len(val):
cls._values[key] = [ v() for v in val ]
- elif isNullPointer(val):
- cls._values[key] = val
- # process param types from _init_dict first, as these may be needed
+ cls._params.parent = sob[0]._params
+ cls._values.parent = sob[0]._values
+
+ elif len(sob) > 1:
+ panic("""\
+The config hierarchy only supports single inheritence of SimObject
+classes. You're trying to derive from:
+%s""" % str(sob))
+
+ # process param types from _init_dict, as these may be needed
# by param descriptions also in _init_dict
for key,val in cls._init_dict.items():
if isinstance(val, type) and issubclass(val, ParamType):
@@ -362,9 +375,7 @@ class MetaConfigNode(type):
for key,val in cls._init_dict.items():
# param descriptions
if isinstance(val, _Param):
- cls._params[key] = val
- # try to resolve local param types in local param_types scope
- val.maybe_resolve_type(cls._param_types)
+ cls._new_param(key, val)
# init-time-only keywords
elif cls.init_keywords.has_key(key):
@@ -387,99 +398,6 @@ class MetaConfigNode(type):
else:
setattr(cls, key, val)
-
- def _isvalue(cls, name):
- for c in cls._bases:
- if c._params.has_key(name):
- return True
-
- for c in cls._bases:
- if c._values.has_key(name):
- return True
-
- return False
-
- # generator that iterates across all parameters for this class and
- # all classes it inherits from
- def _getparams(cls):
- params = {}
- for c in cls._bases:
- for p,v in c._params.iteritems():
- if not params.has_key(p):
- params[p] = v
- return params
-
- # Lookup a parameter description by name in the given class.
- def _getparam(cls, name, default = AttributeError):
- for c in cls._bases:
- if c._params.has_key(name):
- return c._params[name]
- if isSubClass(default, Exception):
- raise default, \
- "object '%s' has no attribute '%s'" % (cls.__name__, name)
- else:
- return default
-
- def _hasvalue(cls, name):
- for c in cls._bases:
- if c._values.has_key(name):
- return True
-
- return False
-
- def _getvalues(cls):
- values = {}
- for i,c in enumerate(cls._bases):
- for p,v in c._values.iteritems():
- if not values.has_key(p):
- values[p] = v
- for p,v in c._params.iteritems():
- if not values.has_key(p) and hasattr(v, 'default'):
- try:
- v.valid(v.default)
- except TypeError:
- panic("Invalid default %s for param %s in node %s"
- % (v.default,p,cls.__name__))
- v = v.default
- cls._setvalue(p, v)
- values[p] = v
-
- return values
-
- def _getvalue(cls, name, default = AttributeError):
- value = None
- for c in cls._bases:
- if c._values.has_key(name):
- value = c._values[name]
- break
- if value is not None:
- return value
-
- param = cls._getparam(name, None)
- if param is not None and hasattr(param, 'default'):
- param.valid(param.default)
- value = param.default
- cls._setvalue(name, value)
- return value
-
- if isSubClass(default, Exception):
- raise default, 'value for %s not found' % name
- else:
- return default
-
- def _setvalue(cls, name, value):
- cls._values[name] = value
-
- def __getattr__(cls, attr):
- if cls._isvalue(attr):
- return Value(cls, attr)
-
- if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
- return cls.type + '*'
-
- raise AttributeError, \
- "object '%s' has no attribute '%s'" % (cls.__name__, attr)
-
def _set_keyword(cls, keyword, val, kwtype):
if not isinstance(val, kwtype):
raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
@@ -488,6 +406,13 @@ class MetaConfigNode(type):
val = classmethod(val)
type.__setattr__(cls, keyword, val)
+ def _new_param(cls, name, value):
+ cls._params[name] = value
+ if hasattr(value, 'default'):
+ cls._values[name] = value.default
+ # try to resolve local param types in local param_types scope
+ value.maybe_resolve_type(cls._param_types)
+
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
def __setattr__(cls, attr, value):
@@ -501,23 +426,33 @@ class MetaConfigNode(type):
return
# must be SimObject param
- param = cls._getparam(attr, None)
+ param = cls._params.get(attr, None)
if param:
# It's ok: set attribute by delegating to 'object' class.
# Note the use of param.make_value() to verify/canonicalize
# the assigned value
try:
param.valid(value)
- except:
- panic("Error setting param %s.%s to %s\n" % \
- (cls.__name__, attr, value))
- cls._setvalue(attr, value)
+ except Exception, e:
+ panic("Exception: %s\nError setting param %s.%s to %s\n" % \
+ (e, cls.__name__, attr, value))
+ cls._values[attr] = value
elif isConfigNode(value) or isSimObjSequence(value):
- cls._setvalue(attr, value)
+ cls._values[attr] = value
else:
raise AttributeError, \
"Class %s has no parameter %s" % (cls.__name__, attr)
+ def __getattr__(cls, attr):
+ if cls._params.has_key(attr) or cls._values.has_key(attr):
+ return Value(cls, attr)
+
+ if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
+ return cls.type + '*'
+
+ raise AttributeError, \
+ "object '%s' has no attribute '%s'" % (cls.__name__, attr)
+
def add_child(cls, instance, name, child):
if isNullPointer(child) or instance.top_child_names.has_key(name):
return
@@ -547,7 +482,7 @@ class MetaConfigNode(type):
if hasattr(cls, 'check'):
cls.check()
- for key,value in cls._getvalues().iteritems():
+ for key,value in cls._values.iteritems():
if isConfigNode(value):
cls.add_child(instance, key, value)
if isinstance(value, (list, tuple)):
@@ -555,11 +490,10 @@ class MetaConfigNode(type):
if len(vals):
cls.add_child(instance, key, vals)
- for pname,param in cls._getparams().iteritems():
- try:
- value = cls._getvalue(pname)
- except:
- panic('Error getting %s' % pname)
+ for pname,param in cls._params.iteritems():
+ value = cls._values.get(pname, None)
+ if value is None:
+ panic('Error getting %s from %s' % (pname, name))
try:
if isConfigNode(value):
@@ -618,7 +552,7 @@ class ConfigNode(object):
cls._anon_subclass_counter += 1
return cls.__metaclass__(name, (cls, ), kwargs)
-class ParamContext(ConfigNode):
+class ParamContext(ConfigNode,ParamType):
pass
class MetaSimObject(MetaConfigNode):
@@ -879,7 +813,7 @@ class Value(object):
super(Value, self).__setattr__('obj', obj)
def _getattr(self):
- return self.obj._getvalue(self.attr)
+ return self.obj._values.get(self.attr)
def __setattr__(self, attr, value):
setattr(self._getattr(), attr, value)
diff --git a/python/m5/multidict.py b/python/m5/multidict.py
new file mode 100644
index 000000000..d0c27fa8e
--- /dev/null
+++ b/python/m5/multidict.py
@@ -0,0 +1,158 @@
+__all__ = [ 'multidict' ]
+
+class multidict(object):
+ __nodefault = object()
+ def __init__(self, parent = {}, **kwargs):
+ self.dict = dict(**kwargs)
+ self.parent = parent
+ self.deleted = {}
+
+ def __str__(self):
+ return str(dict(self.items()))
+
+ def __repr__(self):
+ return `dict(self.items())`
+
+ def __contains__(self, key):
+ return self.dict.has_key(key) or self.parent.has_key(key)
+
+ def __delitem__(self, key):
+ try:
+ del self.dict[key]
+ except KeyError, e:
+ if key in self.parent:
+ self.deleted[key] = True
+ else:
+ raise KeyError, e
+
+ def __setitem__(self, key, value):
+ self.deleted.pop(key, False)
+ self.dict[key] = value
+
+ def __getitem__(self, key):
+ try:
+ return self.dict[key]
+ except KeyError, e:
+ if not self.deleted.get(key, False) and key in self.parent:
+ return self.parent[key]
+ else:
+ raise KeyError, e
+
+ def __len__(self):
+ return len(self.dict) + len(self.parent)
+
+ def next(self):
+ for key,value in self.dict.items():
+ yield key,value
+
+ if self.parent:
+ for key,value in self.parent.next():
+ if key not in self.dict and key not in self.deleted:
+ yield key,value
+
+ def has_key(self, key):
+ return key in self
+
+ def iteritems(self):
+ for item in self.next():
+ yield item
+
+ def items(self):
+ return [ item for item in self.next() ]
+
+ def iterkeys(self):
+ for key,value in self.next():
+ yield key
+
+ def keys(self):
+ return [ key for key,value in self.next() ]
+
+ def itervalues(self):
+ for key,value in self.next():
+ yield value
+
+ def values(self):
+ return [ value for key,value in self.next() ]
+
+ def get(self, key, default=__nodefault):
+ try:
+ return self[key]
+ except KeyError, e:
+ if default != self.__nodefault:
+ return default
+ else:
+ raise KeyError, e
+
+ def setdefault(self, key, default):
+ try:
+ return self[key]
+ except KeyError:
+ self.deleted.pop(key, False)
+ self.dict[key] = default
+ return default
+
+ def _dump(self):
+ print 'multidict dump'
+ node = self
+ while isinstance(node, multidict):
+ print ' ', node.dict
+ node = node.parent
+
+ def _dumpkey(self, key):
+ values = []
+ node = self
+ while isinstance(node, multidict):
+ if key in node.dict:
+ values.append(node.dict[key])
+ node = node.parent
+ print key, values
+
+if __name__ == '__main__':
+ test1 = multidict()
+ test2 = multidict(test1)
+ test3 = multidict(test2)
+ test4 = multidict(test3)
+
+ test1['a'] = 'test1_a'
+ test1['b'] = 'test1_b'
+ test1['c'] = 'test1_c'
+ test1['d'] = 'test1_d'
+ test1['e'] = 'test1_e'
+
+ test2['a'] = 'test2_a'
+ del test2['b']
+ test2['c'] = 'test2_c'
+ del test1['a']
+
+ test2.setdefault('f', multidict)
+
+ print 'test1>', test1.items()
+ print 'test2>', test2.items()
+ #print test1['a']
+ print test1['b']
+ print test1['c']
+ print test1['d']
+ print test1['e']
+
+ print test2['a']
+ #print test2['b']
+ print test2['c']
+ print test2['d']
+ print test2['e']
+
+ for key in test2.iterkeys():
+ print key
+
+ test2.get('g', 'foo')
+ #test2.get('b')
+ test2.get('b', 'bar')
+ test2.setdefault('b', 'blah')
+ print test1
+ print test2
+ print `test2`
+
+ print len(test2)
+
+ test3['a'] = [ 0, 1, 2, 3 ]
+
+ print test4