root/masterdriverz/snakeoil-formatters/snakeoil/iterables.py @ masterdriverz%2540gentoo.org-20070503195038-5awt00roswvtfs38

Revision masterdriverz%2540gentoo.org-20070503195038-5awt00roswvtfs38, 6.3 kB (checked in by Charlie Shepherd <masterdriverz@…>, 21 months ago)

Revert/fix my stupid mistakes

Line 
1# Copyright: 2006 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4from collections import deque
5
6class expandable_chain(object):
7    """
8    chained iterables, with the ability to add new iterables to the chain
9    as long as the instance hasn't raised StopIteration already.
10    """
11
12    __slot__ = ("iterables", "__weakref__")
13
14    def __init__(self, *iterables):
15        """
16        accepts N iterables, must have at least one specified
17        """
18        self.iterables = deque()
19        self.extend(iterables)
20
21    def __iter__(self):
22        return self
23
24    def next(self):
25        if self.iterables is not None:
26            while self.iterables:
27                try:
28                    return self.iterables[0].next()
29                except StopIteration:
30                    self.iterables.popleft()
31            self.iterables = None
32        raise StopIteration()
33
34    def append(self, iterable):
35        """append an iterable to the chain to be consumed"""
36        if self.iterables is None:
37            raise StopIteration()
38        self.iterables.append(iter(iterable))
39
40    def appendleft(self, iterable):
41        """prepend an iterable to the chain to be consumed"""
42        if self.iterables is None:
43            raise StopIteration()
44        self.iterables.appendleft(iter(iterable))
45
46    def extend(self, iterables):
47        """extend multiple iterables to the chain to be consumed"""
48        if self.iterables is None:
49            raise StopIteration()
50        self.iterables.extend(iter(x) for x in iterables)
51
52    def extendleft(self, iterables):
53        """prepend multiple iterables to the chain to be consumed"""
54        if self.iterables is None:
55            raise StopIteration()
56        self.iterables.extendleft(iter(x) for x in iterables)
57
58
59class caching_iter(object):
60    """
61    On demand consumes from an iterable so as to appear like a tuple
62    """
63    __slots__ = ("iterable", "__weakref__", "cached_list", "sorter")
64
65    def __init__(self, iterable, sorter=None):
66        self.sorter = sorter
67        self.iterable = iter(iterable)
68        self.cached_list = []
69
70    def __setitem__(self, key, val):
71        raise TypeError("non modifiable")
72
73    def __getitem__(self, index):
74        existing_len = len(self.cached_list)
75        if self.iterable is not None and self.sorter:
76            self.cached_list.extend(self.iterable)
77            self.cached_list = tuple(self.sorter(self.cached_list))
78            self.iterable = self.sorter = None
79            existing_len = len(self.cached_list)
80
81        if index < 0:
82            if self.iterable is not None:
83                self.cached_list = tuple(self.cached_list + list(self.iterable))
84                self.iterable = None
85                existing_len = len(self.cached_list)
86
87            index = existing_len + index
88            if index < 0:
89                raise IndexError("list index out of range")
90
91        elif index >= existing_len - 1:
92            if self.iterable is not None:
93                try:
94                    self.cached_list.extend(self.iterable.next()
95                        for i in xrange(existing_len - index + 1))
96                except StopIteration:
97                    # consumed, baby.
98                    self.iterable = None
99                    self.cached_list = tuple(self.cached_list)
100                    raise IndexError("list index out of range")
101
102        return self.cached_list[index]
103
104    def __cmp__(self, other):
105        if self.iterable is not None:
106            if self.sorter:
107                self.cached_list.extend(self.iterable)
108                self.cached_list = tuple(self.sorter(self.cached_list))
109                self.sorter = None
110            else:
111                self.cached_list = tuple(self.cached_list + list(self.iterable))
112            self.iterable = None
113        return cmp(self.cached_list, other)
114
115    def __nonzero__(self):
116        if self.cached_list:
117            return True
118
119        if self.iterable:
120            for x in self.iterable:
121                self.cached_list.append(x)
122                return True
123            # if we've made it here... then nothing more in the iterable.
124            self.iterable = self.sorter = None
125            self.cached_list = ()
126        return False
127
128    def __len__(self):
129        if self.iterable is not None:
130            self.cached_list.extend(self.iterable)
131            if self.sorter:
132                self.cached_list = tuple(self.sorter(self.cached_list))
133                self.sorter = None
134            else:
135                self.cached_list = tuple(self.cached_list)
136            self.iterable = None
137        return len(self.cached_list)
138
139    def __iter__(self):
140        if (self.sorter is not None and
141            self.iterable is not None and
142            len(self.cached_list) == 0):
143            self.cached_list = tuple(self.sorter(self.iterable))
144            self.iterable = self.sorter = None
145
146        for x in self.cached_list:
147            yield x
148        if self.iterable is not None:
149            for x in self.iterable:
150                self.cached_list.append(x)
151                yield x
152        else:
153            return
154        self.iterable = None
155        self.cached_list = tuple(self.cached_list)
156
157    def __hash__(self):
158        if self.iterable is not None:
159            self.cached_list.extend(self.iterable)
160            self.cached_list = tuple(self.cached_list)
161            self.iterable = None
162        return hash(self.cached_list)
163
164    def __str__(self):
165        return "iterable(%s), cached: %s" % (
166            self.iterable, str(self.cached_list))
167
168def iter_sort(sorter, *iterables):
169    """Merge a number of sorted iterables into a single sorted iterable.
170
171    @type  sorter: callable.
172    @param sorter: function, passed a list of [element, iterable].
173    @param iterables: iterables to consume from.
174        B{Required} to yield in presorted order.
175    """
176    l = []
177    for x in iterables:
178        try:
179            x = iter(x)
180            l.append([x.next(), x])
181        except StopIteration:
182            pass
183    if len(l) == 1:
184        yield l[0][0]
185        for x in l[0][1]:
186            yield x
187        return
188    l = sorter(l)
189    while l:
190        yield l[0][0]
191        for y in l[0][1]:
192            l[0][0] = y
193            break
194        else:
195            del l[0]
196            if len(l) == 1:
197                yield l[0][0]
198                for x in l[0][1]:
199                    yield x
200                break
201            continue
202        l = sorter(l)
Note: See TracBrowser for help on using the browser.