python: Refactor toNum to support a selection of units

Add support for matching one of several different units in toNum. The
units parameter can now either be a tuple or a string describing the
supported unit(s). The function now returns a (magnitude, unit) tuple.

Change-Id: I683819722a93ade91a6def2bfa77209c29b4b39e
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/39217
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Gabe Black <gabe.black@gmail.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
This commit is contained in:
Andreas Sandberg
2021-01-18 19:04:39 +00:00
parent 7a5be9aae7
commit c9bd435e38

View File

@@ -1,3 +1,15 @@
# Copyright (c) 2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2005 The Regents of The University of Michigan
# Copyright (c) 2010 Advanced Micro Devices, Inc.
# All rights reserved.
@@ -88,9 +100,40 @@ def assertStr(value):
if not isinstance(value, str):
raise TypeError("wrong type '%s' should be str" % type(value))
def _split_suffix(value, suffixes):
'''Split a string based on a suffix from a list of suffixes.
:param value: String value to test for a matching suffix.
:param suffixes: Container of suffixes to test.
:returns: A tuple of (value, suffix). Suffix is the empty string
if there is no match.
'''
matches = [ sfx for sfx in suffixes if value.endswith(sfx) ]
assert len(matches) <= 1
return (value[:-len(matches[0])], matches[0]) if matches \
else (value, '')
# memory size configuration stuff
def toNum(value, target_type, units, prefixes, converter):
'''Convert a string using units and prefixes to (typically) a float or
integer.
String values are assumed to either be a naked magnitude without a
unit or prefix, or a magnitude with a unit and an optional prefix.
:param value: String value to convert.
:param target_type: Type name for error messages.
:param units: Unit (string) or list of valid units.
:param prefixes: Mapping of prefixes to multipliers.
:param converter: Helper function to convert magnitude to native
type.
:returns: Tuple of (converted value, unit)
'''
assertStr(value)
def convert(val):
@@ -100,22 +143,28 @@ def toNum(value, target_type, units, prefixes, converter):
raise ValueError(
"cannot convert '%s' to %s" % (value, target_type))
if units and not value.endswith(units):
units = None
# Units can be None, the empty string, or a list/tuple. Convert
# to a tuple for consistent handling.
if not units:
return convert(value)
units = tuple()
elif isinstance(units, str):
units = (units,)
else:
units = tuple(units)
value = value[:-len(units)]
magnitude_prefix, unit = _split_suffix(value, units)
prefix = next((p for p in prefixes.keys() if value.endswith(p)), None)
if not prefix:
return convert(value)
value = value[:-len(prefix)]
# We only allow a prefix if there is a unit
if unit:
magnitude, prefix = _split_suffix(magnitude_prefix, prefixes)
scale = prefixes[prefix] if prefix else 1
else:
magnitude, prefix, scale = magnitude_prefix, '', 1
return convert(value) * prefixes[prefix]
return convert(magnitude) * scale, unit
def toFloat(value, target_type='float', units=None, prefixes=[]):
return toNum(value, target_type, units, prefixes, float)
return toNum(value, target_type, units, prefixes, float)[0]
def toMetricFloat(value, target_type='float', units=None):
return toFloat(value, target_type, units, metric_prefixes)
@@ -124,8 +173,8 @@ def toBinaryFloat(value, target_type='float', units=None):
return toFloat(value, target_type, units, binary_prefixes)
def toInteger(value, target_type='integer', units=None, prefixes=[]):
intifier = lambda x: int(x, 0)
return toNum(value, target_type, units, prefixes, intifier)
return toNum(value, target_type, units, prefixes,
lambda x: int(x, 0))[0]
def toMetricInteger(value, target_type='integer', units=None):
return toInteger(value, target_type, units, metric_prefixes)