| # Copyright (c) 2005 The Regents of The University of Michigan |
| # Copyright (c) 2010 Advanced Micro Devices, Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer; |
| # redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution; |
| # neither the name of the copyright holders nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import six |
| if six.PY3: |
| long = int |
| |
| # metric prefixes |
| atto = 1.0e-18 |
| femto = 1.0e-15 |
| pico = 1.0e-12 |
| nano = 1.0e-9 |
| micro = 1.0e-6 |
| milli = 1.0e-3 |
| |
| kilo = 1.0e3 |
| mega = 1.0e6 |
| giga = 1.0e9 |
| tera = 1.0e12 |
| peta = 1.0e15 |
| exa = 1.0e18 |
| |
| # power of 2 prefixes |
| kibi = 1024 |
| mebi = kibi * 1024 |
| gibi = mebi * 1024 |
| tebi = gibi * 1024 |
| pebi = tebi * 1024 |
| exbi = pebi * 1024 |
| |
| metric_prefixes = { |
| 'Ei': exbi, |
| 'E': exa, |
| 'Pi': pebi, |
| 'P': peta, |
| 'Ti': tebi, |
| 'T': tera, |
| 'Gi': gibi, |
| 'G': giga, |
| 'M': mega, |
| 'ki': kibi, |
| 'k': kilo, |
| 'Mi': mebi, |
| 'm': milli, |
| 'u': micro, |
| 'n': nano, |
| 'p': pico, |
| 'f': femto, |
| 'a': atto, |
| } |
| |
| binary_prefixes = { |
| 'Ei': exbi, |
| 'E' : exbi, |
| 'Pi': pebi, |
| 'P' : pebi, |
| 'Ti': tebi, |
| 'T' : tebi, |
| 'Gi': gibi, |
| 'G' : gibi, |
| 'Mi': mebi, |
| 'M' : mebi, |
| 'ki': kibi, |
| 'k' : kibi, |
| } |
| |
| def assertStr(value): |
| if not isinstance(value, str): |
| raise TypeError("wrong type '%s' should be str" % type(value)) |
| |
| |
| # memory size configuration stuff |
| def toNum(value, target_type, units, prefixes, converter): |
| assertStr(value) |
| |
| def convert(val): |
| try: |
| return converter(val) |
| except ValueError: |
| raise ValueError( |
| "cannot convert '%s' to %s" % (value, target_type)) |
| |
| if units and not value.endswith(units): |
| units = None |
| if not units: |
| return convert(value) |
| |
| value = value[:-len(units)] |
| |
| prefix = next((p for p in prefixes.keys() if value.endswith(p)), None) |
| if not prefix: |
| return convert(value) |
| value = value[:-len(prefix)] |
| |
| return convert(value) * prefixes[prefix] |
| |
| def toFloat(value, target_type='float', units=None, prefixes=[]): |
| return toNum(value, target_type, units, prefixes, float) |
| |
| def toMetricFloat(value, target_type='float', units=None): |
| return toFloat(value, target_type, units, metric_prefixes) |
| |
| 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) |
| |
| def toMetricInteger(value, target_type='integer', units=None): |
| return toInteger(value, target_type, units, metric_prefixes) |
| |
| def toBinaryInteger(value, target_type='integer', units=None): |
| return toInteger(value, target_type, units, binary_prefixes) |
| |
| def toBool(value): |
| assertStr(value) |
| |
| value = value.lower() |
| if value in ('true', 't', 'yes', 'y', '1'): |
| return True |
| if value in ('false', 'f', 'no', 'n', '0'): |
| return False |
| return result |
| |
| def toFrequency(value): |
| return toMetricFloat(value, 'frequency', 'Hz') |
| |
| def toLatency(value): |
| return toMetricFloat(value, 'latency', 's') |
| |
| def anyToLatency(value): |
| """result is a clock period""" |
| try: |
| return 1 / toFrequency(value) |
| except (ValueError, ZeroDivisionError): |
| pass |
| |
| try: |
| return toLatency(value) |
| except ValueError: |
| pass |
| |
| raise ValueError("cannot convert '%s' to clock period" % value) |
| |
| def anyToFrequency(value): |
| """result is a clock period""" |
| try: |
| return toFrequency(value) |
| except ValueError: |
| pass |
| |
| try: |
| return 1 / toLatency(value) |
| except ValueError as ZeroDivisionError: |
| pass |
| |
| raise ValueError("cannot convert '%s' to clock period" % value) |
| |
| def toNetworkBandwidth(value): |
| return toMetricFloat(value, 'network bandwidth', 'bps') |
| |
| def toMemoryBandwidth(value): |
| return toBinaryFloat(value, 'memory bandwidth', 'B/s') |
| |
| def toMemorySize(value): |
| return toBinaryInteger(value, 'memory size', 'B') |
| |
| def toIpAddress(value): |
| if not isinstance(value, str): |
| raise TypeError("wrong type '%s' should be str" % type(value)) |
| |
| bytes = value.split('.') |
| if len(bytes) != 4: |
| raise ValueError('invalid ip address %s' % value) |
| |
| for byte in bytes: |
| if not 0 <= int(byte) <= 0xff: |
| raise ValueError('invalid ip address %s' % value) |
| |
| return (int(bytes[0]) << 24) | (int(bytes[1]) << 16) | \ |
| (int(bytes[2]) << 8) | (int(bytes[3]) << 0) |
| |
| def toIpNetmask(value): |
| if not isinstance(value, str): |
| raise TypeError("wrong type '%s' should be str" % type(value)) |
| |
| (ip, netmask) = value.split('/') |
| ip = toIpAddress(ip) |
| netmaskParts = netmask.split('.') |
| if len(netmaskParts) == 1: |
| if not 0 <= int(netmask) <= 32: |
| raise ValueError('invalid netmask %s' % netmask) |
| return (ip, int(netmask)) |
| elif len(netmaskParts) == 4: |
| netmaskNum = toIpAddress(netmask) |
| if netmaskNum == 0: |
| return (ip, 0) |
| testVal = 0 |
| for i in range(32): |
| testVal |= (1 << (31 - i)) |
| if testVal == netmaskNum: |
| return (ip, i + 1) |
| raise ValueError('invalid netmask %s' % netmask) |
| else: |
| raise ValueError('invalid netmask %s' % netmask) |
| |
| def toIpWithPort(value): |
| if not isinstance(value, str): |
| raise TypeError("wrong type '%s' should be str" % type(value)) |
| |
| (ip, port) = value.split(':') |
| ip = toIpAddress(ip) |
| if not 0 <= int(port) <= 0xffff: |
| raise ValueError('invalid port %s' % port) |
| return (ip, int(port)) |
| |
| def toVoltage(value): |
| return toMetricFloat(value, 'voltage', 'V') |
| |
| def toCurrent(value): |
| return toMetricFloat(value, 'current', 'A') |
| |
| def toEnergy(value): |
| return toMetricFloat(value, 'energy', 'J') |