proxy.py revision 3101
1# Copyright (c) 2004-2006 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Steve Reinhardt
28#          Nathan Binkert
29
30#####################################################################
31#
32# Proxy object support.
33#
34#####################################################################
35
36class BaseProxy(object):
37    def __init__(self, search_self, search_up):
38        self._search_self = search_self
39        self._search_up = search_up
40        self._multiplier = None
41
42    def __setattr__(self, attr, value):
43        if not attr.startswith('_'):
44            raise AttributeError, 'cannot set attribute on proxy object'
45        super(BaseProxy, self).__setattr__(attr, value)
46
47    # support multiplying proxies by constants
48    def __mul__(self, other):
49        if not isinstance(other, (int, long, float)):
50            raise TypeError, "Proxy multiplier must be integer"
51        if self._multiplier == None:
52            self._multiplier = other
53        else:
54            # support chained multipliers
55            self._multiplier *= other
56        return self
57
58    __rmul__ = __mul__
59
60    def _mulcheck(self, result):
61        if self._multiplier == None:
62            return result
63        return result * self._multiplier
64
65    def unproxy(self, base):
66        obj = base
67        done = False
68
69        if self._search_self:
70            result, done = self.find(obj)
71
72        if self._search_up:
73            while not done:
74                obj = obj._parent
75                if not obj:
76                    break
77                result, done = self.find(obj)
78
79        if not done:
80            raise AttributeError, \
81                  "Can't resolve proxy '%s' of type '%s' from '%s'" % \
82                  (self.path(), self._pdesc.ptype_str, base.path())
83
84        if isinstance(result, BaseProxy):
85            if result == self:
86                raise RuntimeError, "Cycle in unproxy"
87            result = result.unproxy(obj)
88
89        return self._mulcheck(result)
90
91    def getindex(obj, index):
92        if index == None:
93            return obj
94        try:
95            obj = obj[index]
96        except TypeError:
97            if index != 0:
98                raise
99            # if index is 0 and item is not subscriptable, just
100            # use item itself (so cpu[0] works on uniprocessors)
101        return obj
102    getindex = staticmethod(getindex)
103
104    def set_param_desc(self, pdesc):
105        self._pdesc = pdesc
106
107class AttrProxy(BaseProxy):
108    def __init__(self, search_self, search_up, attr):
109        super(AttrProxy, self).__init__(search_self, search_up)
110        self._attr = attr
111        self._modifiers = []
112
113    def __getattr__(self, attr):
114        # python uses __bases__ internally for inheritance
115        if attr.startswith('_'):
116            return super(AttrProxy, self).__getattr__(self, attr)
117        if hasattr(self, '_pdesc'):
118            raise AttributeError, "Attribute reference on bound proxy"
119        self._modifiers.append(attr)
120        return self
121
122    # support indexing on proxies (e.g., Self.cpu[0])
123    def __getitem__(self, key):
124        if not isinstance(key, int):
125            raise TypeError, "Proxy object requires integer index"
126        self._modifiers.append(key)
127        return self
128
129    def find(self, obj):
130        try:
131            val = getattr(obj, self._attr)
132        except:
133            return None, False
134        while isproxy(val):
135            val = val.unproxy(obj)
136        for m in self._modifiers:
137            if isinstance(m, str):
138                val = getattr(val, m)
139            elif isinstance(m, int):
140                val = val[m]
141            else:
142                assert("Item must be string or integer")
143            while isproxy(val):
144                val = val.unproxy(obj)
145        return val, True
146
147    def path(self):
148        p = self._attr
149        for m in self._modifiers:
150            if isinstance(m, str):
151                p += '.%s' % m
152            elif isinstance(m, int):
153                p += '[%d]' % m
154            else:
155                assert("Item must be string or integer")
156        return p
157
158class AnyProxy(BaseProxy):
159    def find(self, obj):
160        return obj.find_any(self._pdesc.ptype)
161
162    def path(self):
163        return 'any'
164
165def isproxy(obj):
166    if isinstance(obj, (BaseProxy, params.EthernetAddr)):
167        return True
168    elif isinstance(obj, (list, tuple)):
169        for v in obj:
170            if isproxy(v):
171                return True
172    return False
173
174class ProxyFactory(object):
175    def __init__(self, search_self, search_up):
176        self.search_self = search_self
177        self.search_up = search_up
178
179    def __getattr__(self, attr):
180        if attr == 'any':
181            return AnyProxy(self.search_self, self.search_up)
182        else:
183            return AttrProxy(self.search_self, self.search_up, attr)
184
185# global objects for handling proxies
186Parent = ProxyFactory(search_self = False, search_up = True)
187Self = ProxyFactory(search_self = True, search_up = False)
188
189# limit exports on 'from proxy import *'
190__all__ = ['Parent', 'Self']
191
192# see comment on imports at end of __init__.py.
193import params # for EthernetAddr
194