convert.py revision 13696:b303ca652433
1# Copyright (c) 2005 The Regents of The University of Michigan
2# Copyright (c) 2010 Advanced Micro Devices, Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28# Authors: Nathan Binkert
29#          Gabe Black
30
31# metric prefixes
32atto  = 1.0e-18
33femto = 1.0e-15
34pico  = 1.0e-12
35nano  = 1.0e-9
36micro = 1.0e-6
37milli = 1.0e-3
38
39kilo = 1.0e3
40mega = 1.0e6
41giga = 1.0e9
42tera = 1.0e12
43peta = 1.0e15
44exa  = 1.0e18
45
46# power of 2 prefixes
47kibi = 1024
48mebi = kibi * 1024
49gibi = mebi * 1024
50tebi = gibi * 1024
51pebi = tebi * 1024
52exbi = pebi * 1024
53
54metric_prefixes = {
55    'Ei': exbi,
56    'E': exa,
57    'Pi': pebi,
58    'P': peta,
59    'Ti': tebi,
60    'T': tera,
61    'Gi': gibi,
62    'G': giga,
63    'M': mega,
64    'ki': kibi,
65    'k': kilo,
66    'Mi': mebi,
67    'm': milli,
68    'u': micro,
69    'n': nano,
70    'p': pico,
71    'f': femto,
72    'a': atto,
73}
74
75binary_prefixes = {
76    'Ei': exbi,
77    'E' : exbi,
78    'Pi': pebi,
79    'P' : pebi,
80    'Ti': tebi,
81    'T' : tebi,
82    'Gi': gibi,
83    'G' : gibi,
84    'Mi': mebi,
85    'M' : mebi,
86    'ki': kibi,
87    'k' : kibi,
88}
89
90def assertStr(value):
91    if not isinstance(value, str):
92        raise TypeError("wrong type '%s' should be str" % type(value))
93
94
95# memory size configuration stuff
96def toNum(value, target_type, units, prefixes, converter):
97    assertStr(value)
98
99    def convert(val):
100        try:
101            return converter(val)
102        except ValueError:
103            raise ValueError(
104                "cannot convert '%s' to %s" % (value, target_type))
105
106    if units and not value.endswith(units):
107        units = None
108    if not units:
109        return convert(value)
110
111    value = value[:-len(units)]
112
113    prefix = next((p for p in prefixes.keys() if value.endswith(p)), None)
114    if not prefix:
115        return convert(value)
116    value = value[:-len(prefix)]
117
118    return convert(value) * prefixes[prefix]
119
120def toFloat(value, target_type='float', units=None, prefixes=[]):
121    return toNum(value, target_type, units, prefixes, float)
122
123def toMetricFloat(value, target_type='float', units=None):
124    return toFloat(value, target_type, units, metric_prefixes)
125
126def toBinaryFloat(value, target_type='float', units=None):
127    return toFloat(value, target_type, units, binary_prefixes)
128
129def toInteger(value, target_type='integer', units=None, prefixes=[]):
130    intifier = lambda x: int(x, 0)
131    return toNum(value, target_type, units, prefixes, intifier)
132
133def toMetricInteger(value, target_type='integer', units=None):
134    return toInteger(value, target_type, units, metric_prefixes)
135
136def toBinaryInteger(value, target_type='integer', units=None):
137    return toInteger(value, target_type, units, binary_prefixes)
138
139def toBool(value):
140    assertStr(value)
141
142    value = value.lower()
143    if value in ('true', 't', 'yes', 'y', '1'):
144        return True
145    if value in ('false', 'f', 'no', 'n', '0'):
146        return False
147    return result
148
149def toFrequency(value):
150    return toMetricFloat(value, 'frequency', 'Hz')
151
152def toLatency(value):
153    return toMetricFloat(value, 'latency', 's')
154
155def anyToLatency(value):
156    """result is a clock period"""
157    try:
158        return 1 / toFrequency(value)
159    except (ValueError, ZeroDivisionError):
160        pass
161
162    try:
163        return toLatency(value)
164    except ValueError:
165        pass
166
167    raise ValueError("cannot convert '%s' to clock period" % value)
168
169def anyToFrequency(value):
170    """result is a clock period"""
171    try:
172        return toFrequency(value)
173    except ValueError:
174        pass
175
176    try:
177        return 1 / toLatency(value)
178    except ValueError as ZeroDivisionError:
179        pass
180
181    raise ValueError("cannot convert '%s' to clock period" % value)
182
183def toNetworkBandwidth(value):
184    return toMetricFloat(value, 'network bandwidth', 'bps')
185
186def toMemoryBandwidth(value):
187    return toBinaryFloat(value, 'memory bandwidth', 'B/s')
188
189def toMemorySize(value):
190    return toBinaryInteger(value, 'memory size', 'B')
191
192def toIpAddress(value):
193    if not isinstance(value, str):
194        raise TypeError("wrong type '%s' should be str" % type(value))
195
196    bytes = value.split('.')
197    if len(bytes) != 4:
198        raise ValueError('invalid ip address %s' % value)
199
200    for byte in bytes:
201        if not 0 <= int(byte) <= 0xff:
202            raise ValueError('invalid ip address %s' % value)
203
204    return (int(bytes[0]) << 24) | (int(bytes[1]) << 16) | \
205           (int(bytes[2]) << 8)  | (int(bytes[3]) << 0)
206
207def toIpNetmask(value):
208    if not isinstance(value, str):
209        raise TypeError("wrong type '%s' should be str" % type(value))
210
211    (ip, netmask) = value.split('/')
212    ip = toIpAddress(ip)
213    netmaskParts = netmask.split('.')
214    if len(netmaskParts) == 1:
215        if not 0 <= int(netmask) <= 32:
216            raise ValueError('invalid netmask %s' % netmask)
217        return (ip, int(netmask))
218    elif len(netmaskParts) == 4:
219        netmaskNum = toIpAddress(netmask)
220        if netmaskNum == 0:
221            return (ip, 0)
222        testVal = 0
223        for i in range(32):
224            testVal |= (1 << (31 - i))
225            if testVal == netmaskNum:
226                return (ip, i + 1)
227        raise ValueError('invalid netmask %s' % netmask)
228    else:
229        raise ValueError('invalid netmask %s' % netmask)
230
231def toIpWithPort(value):
232    if not isinstance(value, str):
233        raise TypeError("wrong type '%s' should be str" % type(value))
234
235    (ip, port) = value.split(':')
236    ip = toIpAddress(ip)
237    if not 0 <= int(port) <= 0xffff:
238        raise ValueError('invalid port %s' % port)
239    return (ip, int(port))
240
241def toVoltage(value):
242    return toMetricFloat(value, 'voltage', 'V')
243
244def toCurrent(value):
245    return toMetricFloat(value, 'current', 'A')
246
247def toEnergy(value):
248    return toMetricFloat(value, 'energy', 'J')
249