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
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
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
37 if range2[1] < range1[0] or range2[0] > range1[1]:
38 return range1
39
40
41 if contains(range2, range1):
42 return None
43
44
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
56
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
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
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
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
206
207 - def insert(self, position, element):
222
230
231 - def pop(self, position=-1):
246
248 self.insert(len(self), element)
249
251 for e in elements:
252 self.append(e)
253
256
258
259 raise NotImplementedError
260
261 - def sort(self, key=None):
262 raise NotImplementedError
263
265
266 raise NotImplementedError
267
269
270 raise NotImplementedError
271
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
302
303 current_index = property(current_index__get, current_index__set)
304