Allow math on CheckedInt-derived ParamValue classes w/o
losing type information. python/m5/config.py: Allow math on CheckedInt-derived ParamValue classes w/o losing type information. - Make CheckedInt derive from NumericParamValue, and *not* multiply inherit from long - Move CheckedInt bounds check to _check() hook so we can call it when value is updated (not just in constructor) python/m5/convert.py: - make toInteger() return a long, making toLong() unnecessary - toMemorySize should return long rather than float --HG-- extra : convert_revision : c1cf5e15b9ff35d9b573dd545e076fe68afef989
This commit is contained in:
parent
76843fc264
commit
fb4f83809f
|
@ -825,6 +825,40 @@ VectorParam = ParamFactory(VectorParamDesc)
|
||||||
#
|
#
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
|
# superclass for "numeric" parameter values, to emulate math
|
||||||
|
# operations in a type-safe way. e.g., a Latency times an int returns
|
||||||
|
# a new Latency object.
|
||||||
|
class NumericParamValue(ParamValue):
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
def __float__(self):
|
||||||
|
return float(self.value)
|
||||||
|
|
||||||
|
# hook for bounds checking
|
||||||
|
def _check(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
newobj = self.__class__(self)
|
||||||
|
newobj.value *= other
|
||||||
|
newobj._check()
|
||||||
|
return newobj
|
||||||
|
|
||||||
|
__rmul__ = __mul__
|
||||||
|
|
||||||
|
def __div__(self, other):
|
||||||
|
newobj = self.__class__(self)
|
||||||
|
newobj.value /= other
|
||||||
|
newobj._check()
|
||||||
|
return newobj
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
newobj = self.__class__(self)
|
||||||
|
newobj.value -= other
|
||||||
|
newobj._check()
|
||||||
|
return newobj
|
||||||
|
|
||||||
class Range(ParamValue):
|
class Range(ParamValue):
|
||||||
type = int # default; can be overridden in subclasses
|
type = int # default; can be overridden in subclasses
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -891,18 +925,20 @@ class CheckedIntType(type):
|
||||||
# class is subclassed to generate parameter classes with specific
|
# class is subclassed to generate parameter classes with specific
|
||||||
# bounds. Initialization of the min and max bounds is done in the
|
# bounds. Initialization of the min and max bounds is done in the
|
||||||
# metaclass CheckedIntType.__init__.
|
# metaclass CheckedIntType.__init__.
|
||||||
class CheckedInt(long,ParamValue):
|
class CheckedInt(NumericParamValue):
|
||||||
__metaclass__ = CheckedIntType
|
__metaclass__ = CheckedIntType
|
||||||
|
|
||||||
def __new__(cls, value):
|
def _check(self):
|
||||||
if isinstance(value, str):
|
if not self.min <= self.value <= self.max:
|
||||||
value = toInteger(value)
|
|
||||||
|
|
||||||
self = long.__new__(cls, value)
|
|
||||||
|
|
||||||
if not cls.min <= self <= cls.max:
|
|
||||||
raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
|
raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
|
||||||
(cls.min, self, cls.max)
|
(self.min, self.value, self.max)
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
self.value = toInteger(value)
|
||||||
|
elif isinstance(value, (int, long)):
|
||||||
|
self.value = long(value)
|
||||||
|
self._check()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Int(CheckedInt): size = 32; unsigned = False
|
class Int(CheckedInt): size = 32; unsigned = False
|
||||||
|
@ -930,19 +966,28 @@ class Float(ParamValue, float):
|
||||||
class MemorySize(CheckedInt):
|
class MemorySize(CheckedInt):
|
||||||
size = 64
|
size = 64
|
||||||
unsigned = True
|
unsigned = True
|
||||||
def __new__(cls, value):
|
def __init__(self, value):
|
||||||
return super(MemorySize, cls).__new__(cls, toMemorySize(value))
|
if isinstance(value, MemorySize):
|
||||||
|
self.value = value.value
|
||||||
|
else:
|
||||||
|
self.value = toMemorySize(value)
|
||||||
|
self._check()
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class Addr(CheckedInt):
|
class Addr(CheckedInt):
|
||||||
size = 64
|
size = 64
|
||||||
unsigned = True
|
unsigned = True
|
||||||
def __new__(cls, value):
|
def __init__(self, value):
|
||||||
try:
|
if isinstance(value, Addr):
|
||||||
value = long(toMemorySize(value))
|
self.value = value.value
|
||||||
except TypeError:
|
else:
|
||||||
value = long(value)
|
try:
|
||||||
return super(Addr, cls).__new__(cls, value)
|
self.value = toMemorySize(value)
|
||||||
|
except TypeError:
|
||||||
|
self.value = long(value)
|
||||||
|
self._check()
|
||||||
|
return self
|
||||||
|
|
||||||
class AddrRange(Range):
|
class AddrRange(Range):
|
||||||
type = Addr
|
type = Addr
|
||||||
|
@ -1123,29 +1168,6 @@ def tick_check(float_ticks):
|
||||||
#raise ValueError
|
#raise ValueError
|
||||||
return int_ticks
|
return int_ticks
|
||||||
|
|
||||||
# superclass for "numeric" parameter values, to emulate math
|
|
||||||
# operations in a type-safe way. e.g., a Latency times an int returns
|
|
||||||
# a new Latency object.
|
|
||||||
class NumericParamValue(ParamValue):
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.value)
|
|
||||||
|
|
||||||
def __float__(self):
|
|
||||||
return float(self.value)
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
newobj = self.__class__(self)
|
|
||||||
newobj.value *= other
|
|
||||||
return newobj
|
|
||||||
|
|
||||||
__rmul__ = __mul__
|
|
||||||
|
|
||||||
def __div__(self, other):
|
|
||||||
newobj = self.__class__(self)
|
|
||||||
newobj.value /= other
|
|
||||||
return newobj
|
|
||||||
|
|
||||||
|
|
||||||
def getLatency(value):
|
def getLatency(value):
|
||||||
if isinstance(value, Latency) or isinstance(value, Clock):
|
if isinstance(value, Latency) or isinstance(value, Clock):
|
||||||
return value.value
|
return value.value
|
||||||
|
|
|
@ -89,17 +89,9 @@ def toFloat(value):
|
||||||
else:
|
else:
|
||||||
return float(value)
|
return float(value)
|
||||||
|
|
||||||
def toLong(value):
|
|
||||||
value = toFloat(value)
|
|
||||||
result = int(value)
|
|
||||||
if value != result:
|
|
||||||
raise ValueError, "cannot convert '%s' to long" % value
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def toInteger(value):
|
def toInteger(value):
|
||||||
value = toFloat(value)
|
value = toFloat(value)
|
||||||
result = int(value)
|
result = long(value)
|
||||||
if value != result:
|
if value != result:
|
||||||
raise ValueError, "cannot convert '%s' to integer" % value
|
raise ValueError, "cannot convert '%s' to integer" % value
|
||||||
|
|
||||||
|
@ -220,16 +212,16 @@ def toMemorySize(value):
|
||||||
raise TypeError, "wrong type '%s' should be str" % type(value)
|
raise TypeError, "wrong type '%s' should be str" % type(value)
|
||||||
|
|
||||||
if value.endswith('PB'):
|
if value.endswith('PB'):
|
||||||
return float(value[:-2]) * pebi
|
return long(value[:-2]) * pebi
|
||||||
elif value.endswith('TB'):
|
elif value.endswith('TB'):
|
||||||
return float(value[:-2]) * tebi
|
return long(value[:-2]) * tebi
|
||||||
elif value.endswith('GB'):
|
elif value.endswith('GB'):
|
||||||
return float(value[:-2]) * gibi
|
return long(value[:-2]) * gibi
|
||||||
elif value.endswith('MB'):
|
elif value.endswith('MB'):
|
||||||
return float(value[:-2]) * mebi
|
return long(value[:-2]) * mebi
|
||||||
elif value.endswith('kB'):
|
elif value.endswith('kB'):
|
||||||
return float(value[:-2]) * kibi
|
return long(value[:-2]) * kibi
|
||||||
elif value.endswith('B'):
|
elif value.endswith('B'):
|
||||||
return float(value[:-1])
|
return long(value[:-1])
|
||||||
|
|
||||||
raise ValueError, "cannot convert '%s' to memory size" % value
|
raise ValueError, "cannot convert '%s' to memory size" % value
|
||||||
|
|
Loading…
Reference in a new issue