blob: 5683aa1f603ba86cebe32e0f17554c312d5e1686 [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"""
Andreas Wundsam76db0062013-11-15 13:34:41 -080033import logging
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
Rich Lanea06d0c32013-03-25 08:52:03 -070037
38################################################################
39#
40# Debug
41#
42################################################################
43
44def debug(obj):
45 """
Andreas Wundsam76db0062013-11-15 13:34:41 -080046 Legacy logging method. Delegate to logging.debug.
Andreas Wundsam55ecc3c2013-11-15 16:11:52 -080047 Use logging.debug directly in the future.
Rich Lanea06d0c32013-03-25 08:52:03 -070048 """
Andreas Wundsam76db0062013-11-15 13:34:41 -080049 logging.debug(obj)
Rich Lanea06d0c32013-03-25 08:52:03 -070050
51def log(obj):
52 """
Andreas Wundsam76db0062013-11-15 13:34:41 -080053 Legacy logging method. Delegate to logging.info.
54 Use logging.info directly in the future.S
Rich Lanea06d0c32013-03-25 08:52:03 -070055 """
Andreas Wundsam76db0062013-11-15 13:34:41 -080056 logging.info(obj)
Andreas Wundsam2d29c072013-07-16 12:44:03 -070057
58################################################################
59#
60# Memoize
61#
62################################################################
63
64def memoize(obj):
65 """ A function/method decorator that memoizes the result"""
66 cache = obj.cache = {}
67
68 @functools.wraps(obj)
69 def memoizer(*args, **kwargs):
Andreas Wundsamf35ec812013-07-16 13:49:18 -070070 key = args + tuple(kwargs.items())
Andreas Wundsam2d29c072013-07-16 12:44:03 -070071 if key not in cache:
72 cache[key] = obj(*args, **kwargs)
73 return cache[key]
74 return memoizer
75
76################################################################
77#
78# OrderedSet
79#
80################################################################
81
Andreas Wundsam2d29c072013-07-16 12:44:03 -070082class OrderedSet(collections.MutableSet):
83 """
84 A set implementations that retains insertion order. From the receipe
85 http://code.activestate.com/recipes/576694/
86 as referred to in the python documentation
87 """
88
89 def __init__(self, iterable=None):
90 self.end = end = []
91 end += [None, end, end] # sentinel node for doubly linked list
92 self.map = {} # key --> [key, prev, next]
93 if iterable is not None:
94 self |= iterable
95
96 def __len__(self):
97 return len(self.map)
98
99 def __contains__(self, key):
100 return key in self.map
101
102 def add(self, key):
103 if key not in self.map:
104 end = self.end
105 curr = end[1]
106 curr[2] = end[1] = self.map[key] = [key, curr, end]
107
108 def discard(self, key):
109 if key in self.map:
110 key, prev, next = self.map.pop(key)
111 prev[2] = next
112 next[1] = prev
113
114 def __iter__(self):
115 end = self.end
116 curr = end[2]
117 while curr is not end:
118 yield curr[0]
119 curr = curr[2]
120
121 def __reversed__(self):
122 end = self.end
123 curr = end[1]
124 while curr is not end:
125 yield curr[0]
126 curr = curr[1]
127
128 def pop(self, last=True):
129 if not self:
130 raise KeyError('set is empty')
131 key = self.end[1][0] if last else self.end[2][0]
132 self.discard(key)
133 return key
134
135 def __repr__(self):
136 if not self:
137 return '%s()' % (self.__class__.__name__,)
138 return '%s(%r)' % (self.__class__.__name__, list(self))
139
140 def __eq__(self, other):
141 if isinstance(other, OrderedSet):
142 return len(self) == len(other) and list(self) == list(other)
143 return set(self) == set(other)
144
Andreas Wundsam662779f2013-07-30 10:38:53 -0700145################################################################
146#
147# OrderedDefaultDict
148#
149################################################################
150
151class OrderedDefaultDict(collections.OrderedDict):
152 """
153 A Dictionary that maintains insertion order where missing values
154 are provided by a factory function, i.e., a combination of
155 the semantics of collections.defaultdict and collections.OrderedDict.
156 """
157 def __init__(self, default_factory=None, *a, **kw):
158 if (default_factory is not None and
159 not callable(default_factory)):
160 raise TypeError('first argument must be callable')
161 collections.OrderedDict.__init__(self, *a, **kw)
162 self.default_factory = default_factory
163
164 def __getitem__(self, key):
165 try:
166 return collections.OrderedDict.__getitem__(self, key)
167 except KeyError:
168 return self.__missing__(key)
169
170 def __missing__(self, key):
171 if self.default_factory is None:
172 raise KeyError(key)
173 self[key] = value = self.default_factory()
174 return value
175
176 def __reduce__(self):
177 if self.default_factory is None:
178 args = tuple()
179 else:
180 args = self.default_factory,
181 return type(self), args, None, None, self.items()
182
183 def copy(self):
184 return self.__copy__()
185
186 def __copy__(self):
187 return type(self)(self.default_factory, self)
188
189 def __deepcopy__(self, memo):
190 import copy
191 return type(self)(self.default_factory,
192 copy.deepcopy(self.items()))
193 def __repr__(self):
194 return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
195 collections.OrderedDict.__repr__(self))
196
197
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700198def find(func, iterable):
Andreas Wundsam2d29c072013-07-16 12:44:03 -0700199 """
200 find the first item in iterable for which func returns something true'ish.
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700201 @returns None if no item in iterable fulfills the condition
Andreas Wundsam2d29c072013-07-16 12:44:03 -0700202 """
203 for i in iterable:
204 if func(i):
205 return i
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700206 return None
207
208def count(func, iteratable):
209 """
210 count how the number of items in iterable for which func returns something true'ish.
211 """
212 c = 0
213 for i in iterable:
214 if func(i):
215 c +=1
216 return c
Rich Lanef51062b2014-02-24 23:08:26 -0800217
218def chunks(l, n):
219 """
220 Yield successive n-sized chunks from l.
221 From http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
222 """
223 for i in xrange(0, len(l), n):
224 yield l[i:i+n]