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