pythonic-fp-circulararray 5.3.2__py3-none-any.whl → 5.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonic_fp/circulararray/__init__.py +1 -2
- pythonic_fp/circulararray/__init__.pyi +0 -0
- pythonic_fp/circulararray/auto.py +275 -287
- pythonic_fp/circulararray/auto.pyi +12 -3
- pythonic_fp/circulararray/fixed.py +207 -219
- pythonic_fp/circulararray/fixed.pyi +15 -3
- {pythonic_fp_circulararray-5.3.2.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/METADATA +28 -13
- pythonic_fp_circulararray-5.4.0.dist-info/RECORD +11 -0
- pythonic_fp_circulararray-5.3.2.dist-info/RECORD +0 -10
- {pythonic_fp_circulararray-5.3.2.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_circulararray-5.3.2.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,7 +4,10 @@ from typing import overload
|
|
|
4
4
|
__all__ = ['CA', 'ca']
|
|
5
5
|
|
|
6
6
|
class CA[I]:
|
|
7
|
-
|
|
7
|
+
@overload
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
@overload
|
|
10
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
8
11
|
def __iter__(self) -> Iterator[I]: ...
|
|
9
12
|
def __reversed__(self) -> Iterator[I]: ...
|
|
10
13
|
def __bool__(self) -> bool: ...
|
|
@@ -33,8 +36,14 @@ class CA[I]:
|
|
|
33
36
|
def rotl(self, n: int = 1) -> None: ...
|
|
34
37
|
def rotr(self, n: int = 1) -> None: ...
|
|
35
38
|
def map[U](self, f: Callable[[I], U]) -> CA[U]: ...
|
|
36
|
-
|
|
37
|
-
def
|
|
39
|
+
@overload
|
|
40
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
41
|
+
@overload
|
|
42
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
43
|
+
@overload
|
|
44
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
45
|
+
@overload
|
|
46
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
38
47
|
def capacity(self) -> int: ...
|
|
39
48
|
def empty(self) -> None: ...
|
|
40
49
|
def fraction_filled(self) -> float: ...
|
|
@@ -16,50 +16,55 @@
|
|
|
16
16
|
Fixed Storage Capacity
|
|
17
17
|
======================
|
|
18
18
|
|
|
19
|
-
Circular array with fixed storage capacity
|
|
19
|
+
**Circular array with fixed storage capacity.**
|
|
20
20
|
|
|
21
|
-
- O(1) pops and pushes either end
|
|
21
|
+
- O(1) pops and pushes either end
|
|
22
22
|
- O(1) indexing, does not support slicing
|
|
23
23
|
- fixed total storage capacity
|
|
24
|
-
- iterable,
|
|
24
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
25
25
|
- comparisons compare identity before equality, like builtins
|
|
26
26
|
- in boolean context, falsy when either empty or full, otherwise truthy
|
|
27
|
-
-
|
|
27
|
+
- function ``caf`` produces fixed capacity circular array from arguments
|
|
28
28
|
|
|
29
29
|
"""
|
|
30
|
+
|
|
30
31
|
from collections.abc import Callable, Iterable, Iterator
|
|
31
|
-
from typing import cast, Final
|
|
32
|
+
from typing import cast, Final, overload
|
|
33
|
+
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
32
34
|
|
|
33
35
|
__all__ = ['CAF', 'caf']
|
|
34
36
|
|
|
37
|
+
nada: Final[NoValue] = NoValue()
|
|
35
38
|
|
|
36
|
-
class CAF[I]():
|
|
37
39
|
|
|
40
|
+
class CAF[I]:
|
|
38
41
|
__slots__ = '_items', '_cnt', '_cap', '_front', '_rear'
|
|
39
42
|
|
|
43
|
+
@overload
|
|
44
|
+
def __init__(self) -> None: ...
|
|
45
|
+
@overload
|
|
46
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
47
|
+
@overload
|
|
48
|
+
def __init__(self, items: Iterable[I], capacity: int) -> None: ...
|
|
49
|
+
|
|
40
50
|
def __init__(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
capacity: int = 2
|
|
44
|
-
) -> None:
|
|
51
|
+
self, items: Iterable[I | NoValue] | NoValue = nada, capacity: int = 2
|
|
52
|
+
) -> None:
|
|
45
53
|
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
:param items: optional iterable to initial populate circular array
|
|
50
|
-
:param capacity: fixed storage capacity of circular array
|
|
51
|
-
:raises TypeError: if items is not Iterable
|
|
52
|
-
|
|
54
|
+
:param items: "Optional" iterable to initial populate circular array.
|
|
55
|
+
:param capacity: Minimum fixed storage capacity of circular array.
|
|
56
|
+
:raises TypeError: When ``items`` not Iterable,
|
|
53
57
|
"""
|
|
54
58
|
capacity = max(2, capacity)
|
|
55
|
-
if items is
|
|
56
|
-
self._items: list[I |
|
|
59
|
+
if items is nada:
|
|
60
|
+
self._items: list[I | NoValue] = [nada] * capacity
|
|
57
61
|
count = 0
|
|
58
62
|
else:
|
|
59
|
-
|
|
63
|
+
values: list[I | NoValue] = list(cast(Iterable[I | NoValue], items))
|
|
64
|
+
dlist: list[I | NoValue] = list(values)
|
|
60
65
|
count = len(dlist)
|
|
61
66
|
capacity = max(count, capacity)
|
|
62
|
-
self._items = dlist + [
|
|
67
|
+
self._items = dlist + [nada] * (capacity - count)
|
|
63
68
|
self._cap: Final[int] = capacity
|
|
64
69
|
self._cnt = count
|
|
65
70
|
if count == 0:
|
|
@@ -72,16 +77,16 @@ class CAF[I]():
|
|
|
72
77
|
def __iter__(self) -> Iterator[I]:
|
|
73
78
|
if self._cnt > 0:
|
|
74
79
|
(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
capacity,
|
|
81
|
+
rear,
|
|
82
|
+
position,
|
|
83
|
+
current_state,
|
|
79
84
|
) = (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
self._cap,
|
|
86
|
+
self._rear,
|
|
87
|
+
self._front,
|
|
88
|
+
self._items.copy(),
|
|
89
|
+
)
|
|
85
90
|
|
|
86
91
|
while position != rear:
|
|
87
92
|
yield cast(I, current_state[position])
|
|
@@ -91,16 +96,16 @@ class CAF[I]():
|
|
|
91
96
|
def __reversed__(self) -> Iterator[I]:
|
|
92
97
|
if self._cnt > 0:
|
|
93
98
|
(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
capacity,
|
|
100
|
+
front,
|
|
101
|
+
position,
|
|
102
|
+
current_state,
|
|
98
103
|
) = (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
self._cap,
|
|
105
|
+
self._front,
|
|
106
|
+
self._rear,
|
|
107
|
+
self._items.copy(),
|
|
108
|
+
)
|
|
104
109
|
|
|
105
110
|
while position != front:
|
|
106
111
|
yield cast(I, current_state[position])
|
|
@@ -156,16 +161,16 @@ class CAF[I]():
|
|
|
156
161
|
del item_list[idx]
|
|
157
162
|
_ca = CAF(item_list, self._cap)
|
|
158
163
|
(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
self._items,
|
|
165
|
+
self._cnt,
|
|
166
|
+
self._front,
|
|
167
|
+
self._rear,
|
|
163
168
|
) = (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
_ca._items,
|
|
170
|
+
_ca._cnt,
|
|
171
|
+
_ca._front,
|
|
172
|
+
_ca._rear,
|
|
173
|
+
)
|
|
169
174
|
del _ca
|
|
170
175
|
|
|
171
176
|
def __eq__(self, other: object) -> bool:
|
|
@@ -175,161 +180,157 @@ class CAF[I]():
|
|
|
175
180
|
return False
|
|
176
181
|
|
|
177
182
|
(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
front1,
|
|
184
|
+
count1,
|
|
185
|
+
capacity1,
|
|
186
|
+
front2,
|
|
187
|
+
count2,
|
|
188
|
+
capacity2,
|
|
184
189
|
) = (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
self._front,
|
|
191
|
+
self._cnt,
|
|
192
|
+
self._cap,
|
|
193
|
+
other._front,
|
|
194
|
+
other._cnt,
|
|
195
|
+
other._cap,
|
|
196
|
+
)
|
|
192
197
|
|
|
193
198
|
if count1 != count2:
|
|
194
199
|
return False
|
|
195
200
|
|
|
196
201
|
for nn in range(count1):
|
|
197
|
-
if
|
|
202
|
+
if (
|
|
203
|
+
self._items[(front1 + nn) % capacity1]
|
|
204
|
+
is other._items[(front2 + nn) % capacity2]
|
|
205
|
+
):
|
|
198
206
|
continue
|
|
199
|
-
if
|
|
207
|
+
if (
|
|
208
|
+
self._items[(front1 + nn) % capacity1]
|
|
209
|
+
!= other._items[(front2 + nn) % capacity2]
|
|
210
|
+
):
|
|
200
211
|
return False
|
|
201
212
|
return True
|
|
202
213
|
|
|
203
214
|
def pushl(self, item: I) -> None:
|
|
204
|
-
"""
|
|
205
|
-
Push single item onto left side (front) of circular array.
|
|
206
|
-
|
|
207
|
-
:param item: single item pushed onto circular array from left
|
|
208
|
-
:raises ValueError: when called on a full CAF
|
|
215
|
+
"""Push ``item`` on from left.
|
|
209
216
|
|
|
217
|
+
:param item: Single item pushed onto circular array from left (front).
|
|
218
|
+
:raises ValueError: When called on a full ``CAF``.
|
|
210
219
|
"""
|
|
211
220
|
if self._cnt == self._cap:
|
|
212
221
|
msg = 'Method pushl called on a full CAF'
|
|
213
222
|
raise ValueError(msg)
|
|
214
223
|
|
|
215
224
|
(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
self._front,
|
|
226
|
+
self._items[self._front],
|
|
227
|
+
self._cnt,
|
|
219
228
|
) = (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
(self._front - 1) % self._cap,
|
|
230
|
+
item,
|
|
231
|
+
self._cnt + 1,
|
|
232
|
+
)
|
|
224
233
|
|
|
225
234
|
def pushr(self, item: I) -> None:
|
|
226
|
-
"""
|
|
227
|
-
Push a single item onto right side (rear) of circular array.
|
|
228
|
-
|
|
229
|
-
:param item: single item pushed onto circular array from right
|
|
230
|
-
:raises ValueError: when called on a full fixed storage capacity circular array
|
|
235
|
+
"""Push ``item`` on from Right.
|
|
231
236
|
|
|
237
|
+
:param item: Single ``item`` pushed onto circular array from right (rear).
|
|
238
|
+
:raises ValueError: When called on a full fixed storage capacity circular array.
|
|
232
239
|
"""
|
|
233
240
|
if self._cnt == self._cap:
|
|
234
241
|
msg = 'Method pushr called on a full CAF'
|
|
235
242
|
raise ValueError(msg)
|
|
236
243
|
|
|
237
244
|
(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
245
|
+
self._rear,
|
|
246
|
+
self._items[self._rear],
|
|
247
|
+
self._cnt,
|
|
241
248
|
) = (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
249
|
+
(self._rear + 1) % self._cap,
|
|
250
|
+
item,
|
|
251
|
+
self._cnt + 1,
|
|
252
|
+
)
|
|
246
253
|
|
|
247
254
|
def popl(self) -> I:
|
|
248
|
-
"""
|
|
249
|
-
Pop item off left side (front) of circular array.
|
|
250
|
-
|
|
251
|
-
:returns: item popped from left side of circular array
|
|
252
|
-
:raises ValueError: when called on an empty circular array
|
|
255
|
+
"""Pop single item off from left side.
|
|
253
256
|
|
|
257
|
+
:returns: Item popped from left side (front) of circular array.
|
|
258
|
+
:raises ValueError: When called on an empty circular array.
|
|
254
259
|
"""
|
|
255
260
|
if self._cnt > 1:
|
|
256
261
|
(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
d,
|
|
263
|
+
self._items[self._front],
|
|
264
|
+
self._front,
|
|
265
|
+
self._cnt,
|
|
261
266
|
) = (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
+
self._items[self._front],
|
|
268
|
+
nada,
|
|
269
|
+
(self._front + 1) % self._cap,
|
|
270
|
+
self._cnt - 1,
|
|
271
|
+
)
|
|
267
272
|
elif self._cnt == 1:
|
|
268
273
|
(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
+
d,
|
|
275
|
+
self._items[self._front],
|
|
276
|
+
self._cnt,
|
|
277
|
+
self._front,
|
|
278
|
+
self._rear,
|
|
274
279
|
) = (
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
self._items[self._front],
|
|
281
|
+
nada,
|
|
282
|
+
0,
|
|
283
|
+
0,
|
|
284
|
+
self._cap - 1,
|
|
285
|
+
)
|
|
281
286
|
else:
|
|
282
287
|
msg = 'Method popl called on an empty CAF'
|
|
283
288
|
raise ValueError(msg)
|
|
284
289
|
return cast(I, d)
|
|
285
290
|
|
|
286
291
|
def popr(self) -> I:
|
|
287
|
-
"""
|
|
288
|
-
Pop item off right side (rear) of circular array.
|
|
289
|
-
|
|
290
|
-
:returns: item popped from right side of circular array
|
|
291
|
-
:raises ValueError: when called on an empty circular array
|
|
292
|
+
"""Pop single item off from right side.
|
|
292
293
|
|
|
294
|
+
:returns: Item popped from right side (rear) of circular array.
|
|
295
|
+
:raises ValueError: When called on an empty circular array.
|
|
293
296
|
"""
|
|
294
297
|
if self._cnt > 1:
|
|
295
298
|
(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
d,
|
|
300
|
+
self._items[self._rear],
|
|
301
|
+
self._rear,
|
|
302
|
+
self._cnt,
|
|
300
303
|
) = (
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
self._items[self._rear],
|
|
305
|
+
nada,
|
|
306
|
+
(self._rear - 1) % self._cap,
|
|
307
|
+
self._cnt - 1,
|
|
308
|
+
)
|
|
306
309
|
elif self._cnt == 1:
|
|
307
310
|
(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
d,
|
|
312
|
+
self._items[self._front],
|
|
313
|
+
self._cnt,
|
|
314
|
+
self._front,
|
|
315
|
+
self._rear,
|
|
313
316
|
) = (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
317
|
+
self._items[self._front],
|
|
318
|
+
nada,
|
|
319
|
+
0,
|
|
320
|
+
0,
|
|
321
|
+
self._cap - 1,
|
|
322
|
+
)
|
|
320
323
|
else:
|
|
321
324
|
msg = 'Method popr called on an empty CAF'
|
|
322
325
|
raise ValueError(msg)
|
|
323
326
|
return cast(I, d)
|
|
324
327
|
|
|
325
328
|
def popld(self, default: I) -> I:
|
|
326
|
-
"""
|
|
327
|
-
Pop one item from left side of the circular array, provide
|
|
329
|
+
"""Pop one item from left side of the circular array, provide
|
|
328
330
|
a mandatory default value. "Safe" version of popl.
|
|
329
331
|
|
|
330
|
-
:param default:
|
|
331
|
-
:returns:
|
|
332
|
-
|
|
332
|
+
:param default: Item returned if circular array is empty.
|
|
333
|
+
:returns: Item popped from left side or default item if empty.
|
|
333
334
|
"""
|
|
334
335
|
try:
|
|
335
336
|
return self.popl()
|
|
@@ -337,13 +338,11 @@ class CAF[I]():
|
|
|
337
338
|
return default
|
|
338
339
|
|
|
339
340
|
def poprd(self, default: I) -> I:
|
|
340
|
-
"""
|
|
341
|
-
Pop one item from right side of the circular array, provide
|
|
341
|
+
"""Pop one item from right side of the circular array, provide
|
|
342
342
|
a mandatory default value. "Safe" version of popr.
|
|
343
343
|
|
|
344
|
-
:param default:
|
|
345
|
-
:returns:
|
|
346
|
-
|
|
344
|
+
:param default: Item returned if circular array is empty.
|
|
345
|
+
:returns: Item popped from right side or default item if empty.
|
|
347
346
|
"""
|
|
348
347
|
try:
|
|
349
348
|
return self.popr()
|
|
@@ -351,12 +350,10 @@ class CAF[I]():
|
|
|
351
350
|
return default
|
|
352
351
|
|
|
353
352
|
def poplt(self, maximum: int) -> tuple[I, ...]:
|
|
354
|
-
"""
|
|
355
|
-
Pop multiple items from left side of circular array.
|
|
356
|
-
|
|
357
|
-
:param maximum: maximum number of items to pop, may pop less if not enough items
|
|
358
|
-
:returns: items in the order popped, left to right
|
|
353
|
+
"""Pop multiple items from left side of circular array.
|
|
359
354
|
|
|
355
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items.
|
|
356
|
+
:returns: Tuple of items in the order popped, left to right.
|
|
360
357
|
"""
|
|
361
358
|
item_list: list[I] = []
|
|
362
359
|
|
|
@@ -371,12 +368,10 @@ class CAF[I]():
|
|
|
371
368
|
return tuple(item_list)
|
|
372
369
|
|
|
373
370
|
def poprt(self, maximum: int) -> tuple[I, ...]:
|
|
374
|
-
"""
|
|
375
|
-
Pop multiple items from right side of circular array.
|
|
376
|
-
|
|
377
|
-
:param maximum: maximum number of items to pop, may pop less if not enough items
|
|
378
|
-
:returns: items in the order popped, right to left
|
|
371
|
+
"""Pop multiple items from right side of circular array.
|
|
379
372
|
|
|
373
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items.
|
|
374
|
+
:returns: Tuple of items in the order popped, right to left.
|
|
380
375
|
"""
|
|
381
376
|
item_list: list[I] = []
|
|
382
377
|
while maximum > 0:
|
|
@@ -389,11 +384,9 @@ class CAF[I]():
|
|
|
389
384
|
return tuple(item_list)
|
|
390
385
|
|
|
391
386
|
def rotl(self, n: int = 1) -> None:
|
|
392
|
-
"""
|
|
393
|
-
Rotate items to the left.
|
|
394
|
-
|
|
395
|
-
:param n: number of times to shift elements to the left
|
|
387
|
+
"""Rotate items to the left.
|
|
396
388
|
|
|
389
|
+
:param n: Number of times to shift elements to the left.
|
|
397
390
|
"""
|
|
398
391
|
if self._cnt < 2:
|
|
399
392
|
return
|
|
@@ -401,122 +394,117 @@ class CAF[I]():
|
|
|
401
394
|
self.pushr(self.popl())
|
|
402
395
|
|
|
403
396
|
def rotr(self, n: int = 1) -> None:
|
|
404
|
-
"""
|
|
405
|
-
Rotate items to the right.
|
|
406
|
-
|
|
407
|
-
:param n: number of times to shift elements to the right
|
|
397
|
+
"""Rotate items to the right.
|
|
408
398
|
|
|
399
|
+
:param n: Number of times to shift elements to the right.
|
|
409
400
|
"""
|
|
410
401
|
if self._cnt < 2:
|
|
411
402
|
return
|
|
412
403
|
for _ in range(n, 0, -1):
|
|
413
404
|
self.pushl(self.popr())
|
|
414
405
|
|
|
415
|
-
def map[U](self, f: Callable[[I], U]) ->
|
|
416
|
-
"""
|
|
417
|
-
Apply function ``f`` over the circular array's contents,
|
|
418
|
-
|
|
419
|
-
:param f: callable from type I to type U
|
|
420
|
-
:returns: new fixed circular array instance
|
|
406
|
+
def map[U](self, f: Callable[[I], U]) -> 'CAF[U]':
|
|
407
|
+
"""Apply function ``f`` over the circular array's contents,
|
|
421
408
|
|
|
409
|
+
:param f: Callable from type ``I`` to type ``U``.
|
|
410
|
+
:returns: New fixed capacity circular array instance.
|
|
422
411
|
"""
|
|
423
412
|
return CAF(map(f, self), self._cap)
|
|
424
413
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
414
|
+
@overload
|
|
415
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
416
|
+
@overload
|
|
417
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
428
418
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
:returns: reduced value produced by the left fold
|
|
432
|
-
:raises ValueError: when circular array empty and no starting item given
|
|
419
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L | NoValue = nada) -> L:
|
|
420
|
+
"""Fold left with a function and optional stating item.
|
|
433
421
|
|
|
422
|
+
:param f: Folding function, first argument to ``f`` is for the accumulator.
|
|
423
|
+
:param start: Optional starting item.
|
|
424
|
+
:returns: Reduced value produced by the left fold.
|
|
425
|
+
:raises ValueError: When circular array empty and no starting item given.
|
|
434
426
|
"""
|
|
435
427
|
if self._cnt == 0:
|
|
436
|
-
if start is
|
|
428
|
+
if start is nada:
|
|
437
429
|
msg = 'Method foldl called on an empty CAF without a start item.'
|
|
438
430
|
raise ValueError(msg)
|
|
439
|
-
return start
|
|
431
|
+
return cast(L, start)
|
|
440
432
|
|
|
441
|
-
if start is
|
|
433
|
+
if start is nada:
|
|
442
434
|
acc = cast(L, self[0]) # in this case D = L
|
|
443
435
|
for idx in range(1, self._cnt):
|
|
444
436
|
acc = f(acc, self[idx])
|
|
445
437
|
return acc
|
|
446
438
|
|
|
447
|
-
acc = start
|
|
439
|
+
acc = cast(L, start)
|
|
448
440
|
for d in self:
|
|
449
441
|
acc = f(acc, d)
|
|
450
442
|
return acc
|
|
451
443
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
444
|
+
@overload
|
|
445
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
446
|
+
@overload
|
|
447
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
455
448
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
:returns: reduced value produced by the right fold
|
|
459
|
-
:raises ValueError: when circular array empty and no starting item given
|
|
449
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R | NoValue = nada) -> R:
|
|
450
|
+
"""Fold right with a function and an optional starting item.
|
|
460
451
|
|
|
452
|
+
:param f: Folding function, second argument to ``f`` is for the accumulator.
|
|
453
|
+
:param start: Optional starting item.
|
|
454
|
+
:returns: Reduced value produced by the right fold.
|
|
455
|
+
:raises ValueError: When circular array empty and no starting item given.
|
|
461
456
|
"""
|
|
462
457
|
if self._cnt == 0:
|
|
463
|
-
if start is
|
|
458
|
+
if start is nada:
|
|
464
459
|
msg = 'Method foldr called on empty CAF without initial value.'
|
|
465
460
|
raise ValueError(msg)
|
|
466
|
-
return start
|
|
461
|
+
return cast(R, start)
|
|
467
462
|
|
|
468
|
-
if start is
|
|
463
|
+
if start is nada:
|
|
469
464
|
acc = cast(R, self[-1]) # in this case D = R
|
|
470
465
|
for idx in range(self._cnt - 2, -1, -1):
|
|
471
466
|
acc = f(self[idx], acc)
|
|
472
467
|
return acc
|
|
473
468
|
|
|
474
|
-
acc = start
|
|
469
|
+
acc = cast(R, start)
|
|
475
470
|
for d in reversed(self):
|
|
476
471
|
acc = f(d, acc)
|
|
477
472
|
return acc
|
|
478
473
|
|
|
479
474
|
def capacity(self) -> int:
|
|
480
|
-
"""
|
|
481
|
-
Return fixed storage capacity of the circular array.
|
|
482
|
-
|
|
483
|
-
:returns: fixed storage capacity
|
|
475
|
+
"""Return fixed storage capacity of the circular array.
|
|
484
476
|
|
|
477
|
+
:returns: Fixed storage capacity.
|
|
485
478
|
"""
|
|
486
479
|
return self._cap
|
|
487
480
|
|
|
488
481
|
def empty(self) -> None:
|
|
489
|
-
"""
|
|
490
|
-
Empty the circular array."""
|
|
482
|
+
"""Empty the circular array."""
|
|
491
483
|
(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
484
|
+
self._items,
|
|
485
|
+
self._front,
|
|
486
|
+
self._rear,
|
|
487
|
+
self._cnt,
|
|
496
488
|
) = (
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
489
|
+
[nada] * self._cap,
|
|
490
|
+
0,
|
|
491
|
+
self._cap - 1,
|
|
492
|
+
0,
|
|
493
|
+
)
|
|
502
494
|
|
|
503
495
|
def fraction_filled(self) -> float:
|
|
504
|
-
"""
|
|
505
|
-
Find fraction of the storage capacity which is filled.
|
|
506
|
-
|
|
507
|
-
:returns: the ratio count/capacity
|
|
496
|
+
"""Find fraction of the storage capacity which is filled.
|
|
508
497
|
|
|
498
|
+
:returns: The ratio count/capacity.
|
|
509
499
|
"""
|
|
510
500
|
return self._cnt / self._cap
|
|
511
501
|
|
|
512
502
|
|
|
513
503
|
def caf[T](*items: T, capacity: int = 2) -> CAF[T]:
|
|
514
|
-
"""
|
|
515
|
-
Produce a circular array from a variable number of arguments.
|
|
516
|
-
|
|
517
|
-
:param items: initial items for a new circular array
|
|
518
|
-
:param capacity: the minimum storage capacity to set
|
|
519
|
-
:returns: new fixed storage capacity circular array
|
|
504
|
+
"""Produce a circular array from a variable number of arguments.
|
|
520
505
|
|
|
506
|
+
:param items: Initial items for a new fixed capacity :circular array.
|
|
507
|
+
:param capacity: The minimum storage capacity to set.
|
|
508
|
+
:returns: New fixed storage capacity circular array.
|
|
521
509
|
"""
|
|
522
|
-
return CAF(items, capacity
|
|
510
|
+
return CAF(items, capacity=capacity)
|