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
This commit is contained in:
parent
62ce65c378
commit
3583fb6830
|
@ -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)
|
||||
|
|
158
python/m5/multidict.py
Normal file
158
python/m5/multidict.py
Normal file
|
@ -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
|
Loading…
Reference in a new issue