Package elisa :: Package plugins :: Package bad :: Package poblenou_frontend :: Module list_cache
[hide private]
[frames] | no frames]

Source Code for Module elisa.plugins.bad.poblenou_frontend.list_cache

1 -def substract(range1, range2):
2 """ 3 Compute the difference between two ranges (L{range1}[0], L{range1}[1]) and 4 (L{range2}[0], L{range2}[1]) (range1 - range2). 5 6 range1 cannot contain strictly range2. (eg.: (10, 20), (13, 17) is not 7 allowed however (10, 20), (10, 17) is)). 8 9 @param range1: boundaries of the first range 10 @type range1: tuple of int 11 @param range2: boundaries of the second range 12 @type range2: tuple of int 13 14 @rtype: tuple of int or None 15 16 @raises: IndexError if range2 is included in range1 17 @raises: IndexError if range1 or range2 are not valid ranges 18 """ 19 # helpers 20 def is_range(range): 21 return range[0] <= range[1]
22 23 def contains(range1, range2): 24 return range1[0] <= range2[0] and range1[1] >= range2[1] 25 26 def strict_contains(range1, range2): 27 return range1[0] < range2[0] and range1[1] > range2[1] 28 29 # ranges validity 30 if not is_range(range1) or not is_range(range2): 31 raise IndexError 32 33 if strict_contains(range1, range2): 34 raise IndexError 35 36 # empty intersection 37 if range2[1] < range1[0] or range2[0] > range1[1]: 38 return range1 39 40 # range1 included in range2 41 if contains(range2, range1): 42 return None 43 44 # range2 included in range1 45 if contains(range1, range2): 46 if range2[0] > range1[0]: 47 inf = range1[0] 48 sup = range2[0]-1 49 else: 50 inf = range2[1]+1 51 sup = range1[1] 52 53 return (inf, sup) 54 55 # TODO: the general case is covered by the previous one 56 # general case 57 if range2[0] >= range1[0]: 58 inf = range1[0] 59 sup = range2[0]-1 60 61 if range2[1] <= range1[1]: 62 inf = range2[1]+1 63 sup = range1[1] 64 65 return (inf, sup) 66
67 -def cache(total, cached, index):
68 """ 69 Given a L{total} number of elements and a number of L{cached} elements 70 amongst them, compute which elements are currently cached. 71 72 @param total: total number of elements 73 @type total: int 74 @param cached: number of cached elements; inferior to L{total} and odd 75 @type cached: int 76 @param index: the current index; must be between 0 77 and L{total}-1 78 @type index: int 79 @rtype: tuple of int 80 """ 81 if total == 0: 82 return None 83 84 half = cached/2 85 inf = max(index-half, 0) 86 sup = min(index+half, total-1) 87 return (inf, sup)
88
89 -def update_index(total, cached, old_index, new_index):
90 """ 91 Given a L{total} number of elements and a number of L{cached} elements 92 amongst them, compute which currently cached elements have to be removed 93 and which ones have to be added for a change of index. 94 It returns two ranges: the first one for the removed elements, the second 95 one for the added elements (eg.: ((1,3), (5,6)), ((1,3), None)...). 96 97 @param total: total number of elements 98 @type total: int 99 @param cached: number of cached elements; inferior to L{total} and odd 100 @type cached: int 101 @param old_index: the current index before the change; must be between 0 102 and L{total}-1 103 @type old_index: int 104 @param new_index: the current index after the change; must be between 0 105 and L{total}-1 106 @type new_index: int 107 108 @rtype: tuple of tuple of int 109 """ 110 old_cache = cache(total, cached, old_index) 111 new_cache = cache(total, cached, new_index) 112 113 to_add = substract(new_cache, old_cache) 114 to_remove = substract(old_cache, new_cache) 115 116 return (to_remove, to_add)
117
118 -def insert(total, cached, index, inserted):
119 """ 120 Given a L{total} number of elements and a number of L{cached} elements 121 amongst them, compute the index of the cached element that has to be 122 removed for an insertion at index L{inserted}. Returns None if no element 123 has to be removed. 124 125 @param total: total number of elements 126 @type total: int 127 @param cached: number of cached elements; inferior to L{total} and odd 128 @type cached: int 129 @param index: the current index; must be between 0 and L{total}-1 130 @type index: int 131 @param inserted: index of the newly inserted element; must be between 0 132 and L{total} 133 @type inserted: int 134 135 @rtype: int 136 """ 137 range = cache(total, cached, index) 138 if range == None: 139 return None 140 141 if total < cached/2+1: 142 return None 143 144 if inserted < range[0] or inserted > range[1]: 145 return None 146 147 if inserted < index: 148 return range[0] 149 else: 150 return range[1]
151
152 -def remove(total, cached, index, removed):
153 """ 154 Given a L{total} number of elements and a number of L{cached} elements 155 amongst them, compute the index of the cached element that has to be 156 added for a removal at index L{removed}. Returns None if no element 157 has to be added. 158 159 @param total: total number of elements 160 @type total: int 161 @param cached: number of cached elements; inferior to L{total} and odd 162 @type cached: int 163 @param index: the current index; must be between 0 and L{total}-1 164 @type index: int 165 @param removed: index of the newly removed element; must be between 0 166 and L{total} 167 @type removed: int 168 169 @rtype: int 170 """ 171 return insert(total, cached, index, removed)
172 173
174 -class CacheList(list):
175 """ 176 A proxy list which purpose is to delay creation of its elements. In order 177 to achieve that the items inserted are callable that return the actual 178 elements. At any time a given number of elements are really instantiated 179 (cached). 180 Their choice is driven by this number and the L{current_index} in the list. 181 They are chosen so that the item at L{current_index} and those around it 182 are instantiated. 183 184 Example: for 3 cached elements in a list of 10 with current_index = 4, the 185 instantiated elements are the 3rd, 4th and 5th (3, 4, 5). 186 187 @ivar current_index: index of the item currently selected 188 @type current_index: int 189 """ 190
191 - def __init__(self, cached, real_list):
192 """ 193 @param cached: number of cached elements; must be odd 194 @type cached: int 195 @param real_list: list to progressively fill; must be empty 196 @type real_list: list 197 """ 198 list.__init__(self) 199 self._cached = cached 200 self._real_list = real_list 201 self._current_index = 0
202
203 - def _in_real_list(self, key):
204 return key - max(self._current_index, self._cached/2) + \ 205 self._cached/2
206
207 - def insert(self, position, element):
208 list.insert(self, position, element) 209 if len(self._real_list) < self._cached/2+1: 210 self._real_list.insert(position, element()) 211 else: 212 to_remove = insert(len(self), self._cached, \ 213 self._current_index, position) 214 if to_remove != None: 215 if to_remove <= self._current_index: 216 self._real_list.pop(0) 217 else: 218 self._real_list.pop(len(self._real_list)-1) 219 self._real_list.insert(self._in_real_list(position), element()) 220 221 self._update_real_index()
222
223 - def _update_real_index(self):
224 # FIXME: selected_item does not exist everywhere 225 try: 226 index = self._current_index 227 self._real_list.selected_item = self._in_real_list(index) 228 except: 229 pass
230
231 - def pop(self, position=-1):
232 list.pop(self, position) 233 to_add = remove(len(self), self._cached, \ 234 self._current_index, position) 235 236 to_remove = self._in_real_list(position) 237 238 if to_remove >= 0 and to_remove < len(self._real_list): 239 self._real_list.pop(to_remove) 240 241 if to_add != None: 242 element = self[to_add] 243 self._real_list.insert(self._in_real_list(to_add), element()) 244 245 self._update_real_index()
246
247 - def append(self, element):
248 self.insert(len(self), element)
249
250 - def extend(self, elements):
251 for e in elements: 252 self.append(e)
253
254 - def remove(self, element):
255 self.pop(self.index(element))
256
257 - def reverse(self):
258 # FIXME: to implement 259 raise NotImplementedError
260
261 - def sort(self, key=None):
262 raise NotImplementedError
263
264 - def __iadd__(self, elements):
265 # FIXME: to implement 266 raise NotImplementedError
267
268 - def __imul__(self, mult):
269 # FIXME: to implement 270 raise NotImplementedError
271
272 - def current_index__set(self, index):
273 if index < 0 or index >= len(self): 274 return 275 276 old_index = self._current_index 277 new_index = index 278 279 delta = new_index - old_index 280 to_remove, to_add = update_index(len(self), self._cached, \ 281 old_index, new_index) 282 283 if to_add != None: 284 for i in range(to_add[0], to_add[1]+1): 285 element = self[i] 286 if delta >= 1: 287 self._real_list.append(element()) 288 else: 289 self._real_list.insert(0, element()) 290 if to_remove != None: 291 for i in range(to_remove[0], to_remove[1]+1): 292 if delta >= 1: 293 self._real_list.pop(0) 294 else: 295 self._real_list.pop(-1) 296 297 self._current_index = index 298 self._update_real_index()
299
300 - def current_index__get(self):
301 return self._current_index
302 303 current_index = property(current_index__get, current_index__set)
304