blob: 0bf289ee807f51402293fcac61a59171cd349007 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Generic utilities
30
31Intended to be imported into another namespace
32"""
33
Andreas Wundsam662779f2013-07-30 10:38:53 -070034import collections
Andreas Wundsam2d29c072013-07-16 12:44:03 -070035import functools
Rich Lanea06d0c32013-03-25 08:52:03 -070036import sys
37import of_g
38
39
40################################################################
41#
42# Configuration related
43#
44################################################################
45
46def config_check(str, dictionary = of_g.code_gen_config):
47 """
48 Return config value if in dictionary; else return False.
49 @param str The lookup index
50 @param dictionary The dict to check; use code_gen_config if None
51 """
52
53 if str in dictionary:
54 return dictionary[str]
55
56 return False
57
58################################################################
59#
60# Debug
61#
62################################################################
63
64def debug(obj):
65 """
66 Debug output to the current both the log file and debug output
67 @param out_str The stringified output to write
68 """
69 of_g.loxigen_dbg_file.write(str(obj) + "\n")
70 log(obj)
71
72def log(obj):
73 """
74 Log output to the current global log file
75 @param out_str The stringified output to write
76 """
77 of_g.loxigen_log_file.write(str(obj) + "\n")
Andreas Wundsam2d29c072013-07-16 12:44:03 -070078
79################################################################
80#
81# Memoize
82#
83################################################################
84
85def memoize(obj):
86 """ A function/method decorator that memoizes the result"""
87 cache = obj.cache = {}
88
89 @functools.wraps(obj)
90 def memoizer(*args, **kwargs):
Andreas Wundsamf35ec812013-07-16 13:49:18 -070091 key = args + tuple(kwargs.items())
Andreas Wundsam2d29c072013-07-16 12:44:03 -070092 if key not in cache:
93 cache[key] = obj(*args, **kwargs)
94 return cache[key]
95 return memoizer
96
97################################################################
98#
99# OrderedSet
100#
101################################################################
102
Andreas Wundsam2d29c072013-07-16 12:44:03 -0700103class OrderedSet(collections.MutableSet):
104 """
105 A set implementations that retains insertion order. From the receipe
106 http://code.activestate.com/recipes/576694/
107 as referred to in the python documentation
108 """
109
110 def __init__(self, iterable=None):
111 self.end = end = []
112 end += [None, end, end] # sentinel node for doubly linked list
113 self.map = {} # key --> [key, prev, next]
114 if iterable is not None:
115 self |= iterable
116
117 def __len__(self):
118 return len(self.map)
119
120 def __contains__(self, key):
121 return key in self.map
122
123 def add(self, key):
124 if key not in self.map:
125 end = self.end
126 curr = end[1]
127 curr[2] = end[1] = self.map[key] = [key, curr, end]
128
129 def discard(self, key):
130 if key in self.map:
131 key, prev, next = self.map.pop(key)
132 prev[2] = next
133 next[1] = prev
134
135 def __iter__(self):
136 end = self.end
137 curr = end[2]
138 while curr is not end:
139 yield curr[0]
140 curr = curr[2]
141
142 def __reversed__(self):
143 end = self.end
144 curr = end[1]
145 while curr is not end:
146 yield curr[0]
147 curr = curr[1]
148
149 def pop(self, last=True):
150 if not self:
151 raise KeyError('set is empty')
152 key = self.end[1][0] if last else self.end[2][0]
153 self.discard(key)
154 return key
155
156 def __repr__(self):
157 if not self:
158 return '%s()' % (self.__class__.__name__,)
159 return '%s(%r)' % (self.__class__.__name__, list(self))
160
161 def __eq__(self, other):
162 if isinstance(other, OrderedSet):
163 return len(self) == len(other) and list(self) == list(other)
164 return set(self) == set(other)
165
Andreas Wundsam662779f2013-07-30 10:38:53 -0700166################################################################
167#
168# OrderedDefaultDict
169#
170################################################################
171
172class OrderedDefaultDict(collections.OrderedDict):
173 """
174 A Dictionary that maintains insertion order where missing values
175 are provided by a factory function, i.e., a combination of
176 the semantics of collections.defaultdict and collections.OrderedDict.
177 """
178 def __init__(self, default_factory=None, *a, **kw):
179 if (default_factory is not None and
180 not callable(default_factory)):
181 raise TypeError('first argument must be callable')
182 collections.OrderedDict.__init__(self, *a, **kw)
183 self.default_factory = default_factory
184
185 def __getitem__(self, key):
186 try:
187 return collections.OrderedDict.__getitem__(self, key)
188 except KeyError:
189 return self.__missing__(key)
190
191 def __missing__(self, key):
192 if self.default_factory is None:
193 raise KeyError(key)
194 self[key] = value = self.default_factory()
195 return value
196
197 def __reduce__(self):
198 if self.default_factory is None:
199 args = tuple()
200 else:
201 args = self.default_factory,
202 return type(self), args, None, None, self.items()
203
204 def copy(self):
205 return self.__copy__()
206
207 def __copy__(self):
208 return type(self)(self.default_factory, self)
209
210 def __deepcopy__(self, memo):
211 import copy
212 return type(self)(self.default_factory,
213 copy.deepcopy(self.items()))
214 def __repr__(self):
215 return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
216 collections.OrderedDict.__repr__(self))
217
218
Andreas Wundsam2d29c072013-07-16 12:44:03 -0700219def find(iterable, func):
220 """
221 find the first item in iterable for which func returns something true'ish.
222 @raise KeyError if no item in iterable fulfills the condition
223 """
224 for i in iterable:
225 if func(i):
226 return i
227 raise KeyError("Couldn't find value that matches: %s" % repr(func))