pythonic-fp-circulararray 6.0.0__py3-none-any.whl → 6.0.2__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 +12 -13
- pythonic_fp/circulararray/__init__.pyi +0 -0
- pythonic_fp/circulararray/auto.py +230 -138
- pythonic_fp/circulararray/auto.pyi +49 -0
- pythonic_fp/circulararray/fixed.py +196 -109
- pythonic_fp/circulararray/fixed.pyi +39 -0
- {pythonic_fp_circulararray-6.0.0.dist-info → pythonic_fp_circulararray-6.0.2.dist-info}/METADATA +7 -7
- pythonic_fp_circulararray-6.0.2.dist-info/RECORD +11 -0
- pythonic_fp_circulararray-6.0.0.dist-info/RECORD +0 -8
- {pythonic_fp_circulararray-6.0.0.dist-info → pythonic_fp_circulararray-6.0.2.dist-info}/WHEEL +0 -0
- {pythonic_fp_circulararray-6.0.0.dist-info → pythonic_fp_circulararray-6.0.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
2
|
+
from typing import overload
|
|
3
|
+
|
|
4
|
+
__all__ = ['CA', 'ca']
|
|
5
|
+
|
|
6
|
+
class CA[X]:
|
|
7
|
+
def __init__(self, *xs: Iterable[X]) -> None: ...
|
|
8
|
+
def __iter__(self) -> Iterator[X]: ...
|
|
9
|
+
def __reversed__(self) -> Iterator[X]: ...
|
|
10
|
+
def __bool__(self) -> bool: ...
|
|
11
|
+
def __len__(self) -> int: ...
|
|
12
|
+
@overload
|
|
13
|
+
def __getitem__(self, idx: int) -> X: ...
|
|
14
|
+
@overload
|
|
15
|
+
def __getitem__(self, idx: slice) -> CA[X]: ...
|
|
16
|
+
@overload
|
|
17
|
+
def __setitem__(self, idx: int, vals: X) -> None: ...
|
|
18
|
+
@overload
|
|
19
|
+
def __setitem__(self, idx: slice, vals: Iterable[X]) -> None: ...
|
|
20
|
+
@overload
|
|
21
|
+
def __delitem__(self, idx: int) -> None: ...
|
|
22
|
+
@overload
|
|
23
|
+
def __delitem__(self, idx: slice) -> None: ...
|
|
24
|
+
def __eq__(self, other: object) -> bool: ...
|
|
25
|
+
def pushl(self, *xs: X) -> None: ...
|
|
26
|
+
def pushr(self, *xs: X) -> None: ...
|
|
27
|
+
def popl(self) -> X: ...
|
|
28
|
+
def popr(self) -> X: ...
|
|
29
|
+
def popld(self, default: X) -> X: ...
|
|
30
|
+
def poprd(self, default: X) -> X: ...
|
|
31
|
+
def poplt(self, maximum: int) -> tuple[X, ...]: ...
|
|
32
|
+
def poprt(self, maximum: int) -> tuple[X, ...]: ...
|
|
33
|
+
def rotl(self, n: int = 1) -> None: ...
|
|
34
|
+
def rotr(self, n: int = 1) -> None: ...
|
|
35
|
+
def map[Y](self, f: Callable[[X], Y]) -> CA[Y]: ...
|
|
36
|
+
@overload
|
|
37
|
+
def foldl[L](self, f: Callable[[X, X], X]) -> X: ...
|
|
38
|
+
@overload
|
|
39
|
+
def foldl[L](self, f: Callable[[L, X], L], start: L) -> L: ...
|
|
40
|
+
@overload
|
|
41
|
+
def foldr[R](self, f: Callable[[X, X], X]) -> X: ...
|
|
42
|
+
@overload
|
|
43
|
+
def foldr[R](self, f: Callable[[X, R], R], start: R) -> R: ...
|
|
44
|
+
def capacity(self) -> int: ...
|
|
45
|
+
def empty(self) -> None: ...
|
|
46
|
+
def fraction_filled(self) -> float: ...
|
|
47
|
+
def resize(self, minimum_capacity: int = 2) -> None: ...
|
|
48
|
+
|
|
49
|
+
def ca[T](*ts: T) -> CA[T]: ...
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
1
|
+
# Copyright 2023-2026 Geoffrey R. Scheller
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -13,18 +13,15 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
Fixed
|
|
17
|
-
======================
|
|
16
|
+
.. admonition:: Fixed storage capacity circular array CAF
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- in boolean context, falsy when either empty or full, otherwise truthy
|
|
27
|
-
- function ``caf`` produces fixed capacity circular array from arguments
|
|
18
|
+
- O(1) pops and pushes either end
|
|
19
|
+
- O(1) indexing, does not support slicing
|
|
20
|
+
- fixed total storage capacity
|
|
21
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
22
|
+
- comparisons compare identity before equality, like builtins
|
|
23
|
+
- in boolean context, falsy when either empty or full, otherwise truthy
|
|
24
|
+
- function ``caf`` produces fixed capacity circular array from arguments
|
|
28
25
|
|
|
29
26
|
"""
|
|
30
27
|
|
|
@@ -37,27 +34,28 @@ __all__ = ['CAF', 'caf']
|
|
|
37
34
|
nada: Final[NoValue] = NoValue()
|
|
38
35
|
|
|
39
36
|
|
|
40
|
-
class CAF[
|
|
41
|
-
__slots__ = '
|
|
37
|
+
class CAF[X]:
|
|
38
|
+
__slots__ = '_xs', '_cnt', '_cap', '_front', '_rear'
|
|
42
39
|
|
|
43
|
-
def __init__(self, *
|
|
40
|
+
def __init__(self, *xs: Iterable[X], cap: int = 2) -> None:
|
|
44
41
|
"""
|
|
45
|
-
:param
|
|
42
|
+
:param xs: Optionally takes a single iterable to initially populate the circular array.
|
|
46
43
|
:param cap: Minimum fixed storage capacity of circular array.
|
|
47
|
-
:raises TypeError: When ``
|
|
44
|
+
:raises TypeError: When ``xs[0]`` not iterable,
|
|
48
45
|
:raises ValueError: If more than 1 iterable is given.
|
|
46
|
+
|
|
49
47
|
"""
|
|
50
48
|
cap = max(2, cap)
|
|
51
|
-
if (size := len(
|
|
49
|
+
if (size := len(xs)) > 1:
|
|
52
50
|
msg = f'CAF expects at most 1 argument, got {size}'
|
|
53
51
|
raise ValueError(msg)
|
|
54
52
|
if size:
|
|
55
|
-
values: list[
|
|
53
|
+
values: list[X | NoValue] = list(cast(Iterable[X | NoValue], xs[0]))
|
|
56
54
|
cnt = len(values)
|
|
57
55
|
cap = max(cnt, cap)
|
|
58
|
-
self.
|
|
56
|
+
self._xs = values + [nada] * (cap - cnt)
|
|
59
57
|
else:
|
|
60
|
-
self.
|
|
58
|
+
self._xs = [nada] * cap
|
|
61
59
|
cnt = 0
|
|
62
60
|
self._cap: Final[int] = cap
|
|
63
61
|
self._cnt = cnt
|
|
@@ -68,7 +66,7 @@ class CAF[I]:
|
|
|
68
66
|
self._front = 0
|
|
69
67
|
self._rear = cnt - 1
|
|
70
68
|
|
|
71
|
-
def __iter__(self) -> Iterator[
|
|
69
|
+
def __iter__(self) -> Iterator[X]:
|
|
72
70
|
if self._cnt > 0:
|
|
73
71
|
(
|
|
74
72
|
cap,
|
|
@@ -79,15 +77,15 @@ class CAF[I]:
|
|
|
79
77
|
self._cap,
|
|
80
78
|
self._rear,
|
|
81
79
|
self._front,
|
|
82
|
-
self.
|
|
80
|
+
self._xs.copy(),
|
|
83
81
|
)
|
|
84
82
|
|
|
85
83
|
while position != rear:
|
|
86
|
-
yield cast(
|
|
84
|
+
yield cast(X, current_state[position])
|
|
87
85
|
position = (position + 1) % cap
|
|
88
|
-
yield cast(
|
|
86
|
+
yield cast(X, current_state[position])
|
|
89
87
|
|
|
90
|
-
def __reversed__(self) -> Iterator[
|
|
88
|
+
def __reversed__(self) -> Iterator[X]:
|
|
91
89
|
if self._cnt > 0:
|
|
92
90
|
(
|
|
93
91
|
cap,
|
|
@@ -98,18 +96,26 @@ class CAF[I]:
|
|
|
98
96
|
self._cap,
|
|
99
97
|
self._front,
|
|
100
98
|
self._rear,
|
|
101
|
-
self.
|
|
99
|
+
self._xs.copy(),
|
|
102
100
|
)
|
|
103
101
|
|
|
104
102
|
while position != front:
|
|
105
|
-
yield cast(
|
|
103
|
+
yield cast(X, current_state[position])
|
|
106
104
|
position = (position - 1) % cap
|
|
107
|
-
yield cast(
|
|
105
|
+
yield cast(X, current_state[position])
|
|
108
106
|
|
|
109
107
|
def __repr__(self) -> str:
|
|
108
|
+
"""
|
|
109
|
+
:returns: String of the form ``caf(x1, x2, ..., xn)``.
|
|
110
|
+
|
|
111
|
+
"""
|
|
110
112
|
return 'caf(' + ', '.join(map(repr, self)) + ')'
|
|
111
113
|
|
|
112
114
|
def __str__(self) -> str:
|
|
115
|
+
"""
|
|
116
|
+
:returns: String of the form ``(|x1, x2, ..., xn|)``.
|
|
117
|
+
|
|
118
|
+
"""
|
|
113
119
|
return '(|' + ', '.join(map(str, self)) + '|)'
|
|
114
120
|
|
|
115
121
|
def __bool__(self) -> bool:
|
|
@@ -118,13 +124,13 @@ class CAF[I]:
|
|
|
118
124
|
def __len__(self) -> int:
|
|
119
125
|
return self._cnt
|
|
120
126
|
|
|
121
|
-
def __getitem__(self, idx: int) ->
|
|
127
|
+
def __getitem__(self, idx: int) -> X:
|
|
122
128
|
cnt = self._cnt
|
|
123
129
|
if 0 <= idx < cnt:
|
|
124
|
-
return cast(
|
|
130
|
+
return cast(X, self._xs[(self._front + idx) % self._cap])
|
|
125
131
|
|
|
126
132
|
if -cnt <= idx < 0:
|
|
127
|
-
return cast(
|
|
133
|
+
return cast(X, self._xs[(self._front + cnt + idx) % self._cap])
|
|
128
134
|
|
|
129
135
|
if cnt == 0:
|
|
130
136
|
msg0 = 'Trying to get a value from an empty CAF.'
|
|
@@ -135,12 +141,12 @@ class CAF[I]:
|
|
|
135
141
|
msg3 = 'while getting value from a CAF.'
|
|
136
142
|
raise IndexError(msg1 + msg2 + msg3)
|
|
137
143
|
|
|
138
|
-
def __setitem__(self, idx: int, val:
|
|
144
|
+
def __setitem__(self, idx: int, val: X) -> None:
|
|
139
145
|
cnt = self._cnt
|
|
140
146
|
if 0 <= idx < cnt:
|
|
141
|
-
self.
|
|
147
|
+
self._xs[(self._front + idx) % self._cap] = val
|
|
142
148
|
elif -cnt <= idx < 0:
|
|
143
|
-
self.
|
|
149
|
+
self._xs[(self._front + cnt + idx) % self._cap] = val
|
|
144
150
|
else:
|
|
145
151
|
if cnt < 1:
|
|
146
152
|
msg0 = 'Trying to index into an empty CAF.'
|
|
@@ -155,12 +161,12 @@ class CAF[I]:
|
|
|
155
161
|
del item_list[idx]
|
|
156
162
|
_ca = CAF(item_list, cap = self._cap)
|
|
157
163
|
(
|
|
158
|
-
self.
|
|
164
|
+
self._xs,
|
|
159
165
|
self._cnt,
|
|
160
166
|
self._front,
|
|
161
167
|
self._rear,
|
|
162
168
|
) = (
|
|
163
|
-
_ca.
|
|
169
|
+
_ca._xs,
|
|
164
170
|
_ca._cnt,
|
|
165
171
|
_ca._front,
|
|
166
172
|
_ca._rear,
|
|
@@ -168,6 +174,13 @@ class CAF[I]:
|
|
|
168
174
|
del _ca
|
|
169
175
|
|
|
170
176
|
def __eq__(self, other: object) -> bool:
|
|
177
|
+
"""
|
|
178
|
+
:param other: The object to be compared to.
|
|
179
|
+
:returns: ``True`` if object is another ``CAF`` whose items compare
|
|
180
|
+
as equal to the corresponding items in the ``CAF``,
|
|
181
|
+
otherwise ``False``.
|
|
182
|
+
|
|
183
|
+
"""
|
|
171
184
|
if self is other:
|
|
172
185
|
return True
|
|
173
186
|
if not isinstance(other, type(self)):
|
|
@@ -194,22 +207,26 @@ class CAF[I]:
|
|
|
194
207
|
|
|
195
208
|
for nn in range(cnt1):
|
|
196
209
|
if (
|
|
197
|
-
self.
|
|
198
|
-
is other.
|
|
210
|
+
self._xs[(front1 + nn) % cap1]
|
|
211
|
+
is other._xs[(front2 + nn) % cap2]
|
|
199
212
|
):
|
|
200
213
|
continue
|
|
201
214
|
if (
|
|
202
|
-
self.
|
|
203
|
-
!= other.
|
|
215
|
+
self._xs[(front1 + nn) % cap1]
|
|
216
|
+
!= other._xs[(front2 + nn) % cap2]
|
|
204
217
|
):
|
|
205
218
|
return False
|
|
206
219
|
return True
|
|
207
220
|
|
|
208
|
-
def pushl(self, item:
|
|
209
|
-
"""
|
|
221
|
+
def pushl(self, item: X) -> None:
|
|
222
|
+
"""
|
|
223
|
+
.. admonition:: Push left
|
|
224
|
+
|
|
225
|
+
Push single item from the left onto the ``CAF``.
|
|
226
|
+
|
|
227
|
+
:param x: Single item to be pushed onto the front of the circular array from the left.
|
|
228
|
+
:raises ValueError: When called on a full fixed storage capacity circular array.
|
|
210
229
|
|
|
211
|
-
:param item: Single item pushed onto circular array from left (front).
|
|
212
|
-
:raises ValueError: When called on a full ``CAF``.
|
|
213
230
|
"""
|
|
214
231
|
if self._cnt == self._cap:
|
|
215
232
|
msg = 'Method pushl called on a full CAF'
|
|
@@ -217,7 +234,7 @@ class CAF[I]:
|
|
|
217
234
|
|
|
218
235
|
(
|
|
219
236
|
self._front,
|
|
220
|
-
self.
|
|
237
|
+
self._xs[self._front],
|
|
221
238
|
self._cnt,
|
|
222
239
|
) = (
|
|
223
240
|
(self._front - 1) % self._cap,
|
|
@@ -225,11 +242,15 @@ class CAF[I]:
|
|
|
225
242
|
self._cnt + 1,
|
|
226
243
|
)
|
|
227
244
|
|
|
228
|
-
def pushr(self, item:
|
|
229
|
-
"""
|
|
245
|
+
def pushr(self, item: X) -> None:
|
|
246
|
+
"""
|
|
247
|
+
.. admonition:: Push right
|
|
248
|
+
|
|
249
|
+
Push single item from the right onto the ``CAF``.
|
|
230
250
|
|
|
231
|
-
:param
|
|
251
|
+
:param x: Single item to be pushed onto the rear of the circular array from the right.
|
|
232
252
|
:raises ValueError: When called on a full fixed storage capacity circular array.
|
|
253
|
+
|
|
233
254
|
"""
|
|
234
255
|
if self._cnt == self._cap:
|
|
235
256
|
msg = 'Method pushr called on a full CAF'
|
|
@@ -237,7 +258,7 @@ class CAF[I]:
|
|
|
237
258
|
|
|
238
259
|
(
|
|
239
260
|
self._rear,
|
|
240
|
-
self.
|
|
261
|
+
self._xs[self._rear],
|
|
241
262
|
self._cnt,
|
|
242
263
|
) = (
|
|
243
264
|
(self._rear + 1) % self._cap,
|
|
@@ -245,20 +266,24 @@ class CAF[I]:
|
|
|
245
266
|
self._cnt + 1,
|
|
246
267
|
)
|
|
247
268
|
|
|
248
|
-
def popl(self) ->
|
|
249
|
-
"""
|
|
269
|
+
def popl(self) -> X:
|
|
270
|
+
"""
|
|
271
|
+
.. admonition:: Pop left
|
|
272
|
+
|
|
273
|
+
Pop a single items off the left side of the ``CAF``.
|
|
250
274
|
|
|
251
275
|
:returns: Item popped from left side (front) of circular array.
|
|
252
276
|
:raises ValueError: When called on an empty circular array.
|
|
277
|
+
|
|
253
278
|
"""
|
|
254
279
|
if self._cnt > 1:
|
|
255
280
|
(
|
|
256
281
|
d,
|
|
257
|
-
self.
|
|
282
|
+
self._xs[self._front],
|
|
258
283
|
self._front,
|
|
259
284
|
self._cnt,
|
|
260
285
|
) = (
|
|
261
|
-
self.
|
|
286
|
+
self._xs[self._front],
|
|
262
287
|
nada,
|
|
263
288
|
(self._front + 1) % self._cap,
|
|
264
289
|
self._cnt - 1,
|
|
@@ -266,12 +291,12 @@ class CAF[I]:
|
|
|
266
291
|
elif self._cnt == 1:
|
|
267
292
|
(
|
|
268
293
|
d,
|
|
269
|
-
self.
|
|
294
|
+
self._xs[self._front],
|
|
270
295
|
self._cnt,
|
|
271
296
|
self._front,
|
|
272
297
|
self._rear,
|
|
273
298
|
) = (
|
|
274
|
-
self.
|
|
299
|
+
self._xs[self._front],
|
|
275
300
|
nada,
|
|
276
301
|
0,
|
|
277
302
|
0,
|
|
@@ -280,22 +305,26 @@ class CAF[I]:
|
|
|
280
305
|
else:
|
|
281
306
|
msg = 'Method popl called on an empty CAF'
|
|
282
307
|
raise ValueError(msg)
|
|
283
|
-
return cast(
|
|
308
|
+
return cast(X, d)
|
|
284
309
|
|
|
285
|
-
def popr(self) ->
|
|
286
|
-
"""
|
|
310
|
+
def popr(self) -> X:
|
|
311
|
+
"""
|
|
312
|
+
.. admonition:: Pop right
|
|
313
|
+
|
|
314
|
+
Pop a single items off the right side of the ``CAF``.
|
|
287
315
|
|
|
288
316
|
:returns: Item popped from right side (rear) of circular array.
|
|
289
317
|
:raises ValueError: When called on an empty circular array.
|
|
318
|
+
|
|
290
319
|
"""
|
|
291
320
|
if self._cnt > 1:
|
|
292
321
|
(
|
|
293
322
|
d,
|
|
294
|
-
self.
|
|
323
|
+
self._xs[self._rear],
|
|
295
324
|
self._rear,
|
|
296
325
|
self._cnt,
|
|
297
326
|
) = (
|
|
298
|
-
self.
|
|
327
|
+
self._xs[self._rear],
|
|
299
328
|
nada,
|
|
300
329
|
(self._rear - 1) % self._cap,
|
|
301
330
|
self._cnt - 1,
|
|
@@ -303,12 +332,12 @@ class CAF[I]:
|
|
|
303
332
|
elif self._cnt == 1:
|
|
304
333
|
(
|
|
305
334
|
d,
|
|
306
|
-
self.
|
|
335
|
+
self._xs[self._front],
|
|
307
336
|
self._cnt,
|
|
308
337
|
self._front,
|
|
309
338
|
self._rear,
|
|
310
339
|
) = (
|
|
311
|
-
self.
|
|
340
|
+
self._xs[self._front],
|
|
312
341
|
nada,
|
|
313
342
|
0,
|
|
314
343
|
0,
|
|
@@ -317,39 +346,53 @@ class CAF[I]:
|
|
|
317
346
|
else:
|
|
318
347
|
msg = 'Method popr called on an empty CAF'
|
|
319
348
|
raise ValueError(msg)
|
|
320
|
-
return cast(
|
|
349
|
+
return cast(X, d)
|
|
350
|
+
|
|
351
|
+
def popld(self, default: X) -> X:
|
|
352
|
+
"""
|
|
353
|
+
.. admonition:: Pop Left with default
|
|
354
|
+
|
|
355
|
+
Pop a single items off the left side of the ``CAF``.
|
|
321
356
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
357
|
+
:param default: Default value to return if ``CAF`` is empty.
|
|
358
|
+
:returns: Item popped from left side (front) of circular array
|
|
359
|
+
if not empty, otherwise return the provided default
|
|
360
|
+
value.
|
|
325
361
|
|
|
326
|
-
:param default: Item returned if circular array is empty.
|
|
327
|
-
:returns: Item popped from left side or default item if empty.
|
|
328
362
|
"""
|
|
329
363
|
try:
|
|
330
364
|
return self.popl()
|
|
331
365
|
except ValueError:
|
|
332
366
|
return default
|
|
333
367
|
|
|
334
|
-
def poprd(self, default:
|
|
335
|
-
"""
|
|
336
|
-
|
|
368
|
+
def poprd(self, default: X) -> X:
|
|
369
|
+
"""
|
|
370
|
+
.. admonition:: Pop Right with default
|
|
371
|
+
|
|
372
|
+
Pop a single items off the right side of the ``CAF``.
|
|
373
|
+
|
|
374
|
+
:param default: Default value to return if ``CAF`` is empty.
|
|
375
|
+
:returns: Item popped from right side (rear) of circular array
|
|
376
|
+
if not empty, otherwise return the provided default
|
|
377
|
+
value.
|
|
337
378
|
|
|
338
|
-
:param default: Item returned if circular array is empty.
|
|
339
|
-
:returns: Item popped from right side or default item if empty.
|
|
340
379
|
"""
|
|
341
380
|
try:
|
|
342
381
|
return self.popr()
|
|
343
382
|
except ValueError:
|
|
344
383
|
return default
|
|
345
384
|
|
|
346
|
-
def poplt(self, maximum: int) -> tuple[
|
|
347
|
-
"""
|
|
385
|
+
def poplt(self, maximum: int) -> tuple[X, ...]:
|
|
386
|
+
"""
|
|
387
|
+
.. admonition:: Pop multiple items from left
|
|
388
|
+
|
|
389
|
+
Pop items off the left side of the ``CAF``.
|
|
390
|
+
|
|
391
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items in ``CAF``.
|
|
392
|
+
:returns: A ``tuple`` of the items popped, left to right.
|
|
348
393
|
|
|
349
|
-
:param maximum: Maximum number of items to pop, may pop less if not enough items.
|
|
350
|
-
:returns: Tuple of items in the order popped, left to right.
|
|
351
394
|
"""
|
|
352
|
-
item_list: list[
|
|
395
|
+
item_list: list[X] = []
|
|
353
396
|
|
|
354
397
|
while maximum > 0:
|
|
355
398
|
try:
|
|
@@ -361,13 +404,17 @@ class CAF[I]:
|
|
|
361
404
|
|
|
362
405
|
return tuple(item_list)
|
|
363
406
|
|
|
364
|
-
def poprt(self, maximum: int) -> tuple[
|
|
365
|
-
"""
|
|
407
|
+
def poprt(self, maximum: int) -> tuple[X, ...]:
|
|
408
|
+
"""
|
|
409
|
+
.. admonition:: Pop multiple items from right
|
|
410
|
+
|
|
411
|
+
Pop items off the right side of the ``CAF``.
|
|
412
|
+
|
|
413
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items in ``CAF``.
|
|
414
|
+
:returns: A ``tuple`` of the items popped, right to left.
|
|
366
415
|
|
|
367
|
-
:param maximum: Maximum number of items to pop, may pop less if not enough items.
|
|
368
|
-
:returns: Tuple of items in the order popped, right to left.
|
|
369
416
|
"""
|
|
370
|
-
item_list: list[
|
|
417
|
+
item_list: list[X] = []
|
|
371
418
|
while maximum > 0:
|
|
372
419
|
try:
|
|
373
420
|
item_list.append(self.popr())
|
|
@@ -378,9 +425,14 @@ class CAF[I]:
|
|
|
378
425
|
return tuple(item_list)
|
|
379
426
|
|
|
380
427
|
def rotl(self, n: int = 1) -> None:
|
|
381
|
-
"""
|
|
428
|
+
"""
|
|
429
|
+
.. admonition:: Rotate left
|
|
430
|
+
|
|
431
|
+
Rotate contents of ``CAF`` to the left putting first
|
|
432
|
+
item onto rear.
|
|
433
|
+
|
|
434
|
+
:param n: Number of times to shift items left. Default 1 time.
|
|
382
435
|
|
|
383
|
-
:param n: Number of times to shift elements to the left.
|
|
384
436
|
"""
|
|
385
437
|
if self._cnt < 2:
|
|
386
438
|
return
|
|
@@ -388,35 +440,48 @@ class CAF[I]:
|
|
|
388
440
|
self.pushr(self.popl())
|
|
389
441
|
|
|
390
442
|
def rotr(self, n: int = 1) -> None:
|
|
391
|
-
"""
|
|
443
|
+
"""
|
|
444
|
+
.. admonition:: Rotate right
|
|
445
|
+
|
|
446
|
+
Rotate contents of ``CAF`` to the right putting last
|
|
447
|
+
item onto front.
|
|
448
|
+
|
|
449
|
+
:param n: Number of times to shift items right. Default 1 time.
|
|
392
450
|
|
|
393
|
-
:param n: Number of times to shift elements to the right.
|
|
394
451
|
"""
|
|
395
452
|
if self._cnt < 2:
|
|
396
453
|
return
|
|
397
454
|
for _ in range(n, 0, -1):
|
|
398
455
|
self.pushl(self.popr())
|
|
399
456
|
|
|
400
|
-
def map[
|
|
401
|
-
"""
|
|
457
|
+
def map[Y](self, f: Callable[[X], Y]) -> 'CAF[Y]':
|
|
458
|
+
"""
|
|
459
|
+
.. admonition:: Map function over the CAF
|
|
460
|
+
|
|
461
|
+
Apply function ``f`` over the circular array's contents.
|
|
402
462
|
|
|
403
|
-
:param f: Callable from type ``
|
|
463
|
+
:param f: Callable from type ``X`` to type ``Y``.
|
|
404
464
|
:returns: New fixed capacity circular array instance.
|
|
465
|
+
|
|
405
466
|
"""
|
|
406
467
|
return CAF(map(f, self), cap = self._cap)
|
|
407
468
|
|
|
408
469
|
@overload
|
|
409
|
-
def foldl[L](self, f: Callable[[
|
|
470
|
+
def foldl[L](self, f: Callable[[X, X], X]) -> X: ...
|
|
410
471
|
@overload
|
|
411
|
-
def foldl[L](self, f: Callable[[L,
|
|
472
|
+
def foldl[L](self, f: Callable[[L, X], L], start: L) -> L: ...
|
|
412
473
|
|
|
413
|
-
def foldl[L](self, f: Callable[[L,
|
|
414
|
-
"""
|
|
474
|
+
def foldl[L](self, f: Callable[[L, X], L], start: L | NoValue = nada) -> L:
|
|
475
|
+
"""
|
|
476
|
+
.. admonition:: Fold left
|
|
477
|
+
|
|
478
|
+
Fold ``CAF`` left with a function and optional starting item.
|
|
415
479
|
|
|
416
480
|
:param f: Folding function, first argument to ``f`` is for the accumulator.
|
|
417
481
|
:param start: Optional starting item.
|
|
418
482
|
:returns: Reduced value produced by the left fold.
|
|
419
|
-
:raises ValueError: When circular array empty and
|
|
483
|
+
:raises ValueError: When circular array empty and ``start`` not given.
|
|
484
|
+
|
|
420
485
|
"""
|
|
421
486
|
if self._cnt == 0:
|
|
422
487
|
if start is nada:
|
|
@@ -436,17 +501,21 @@ class CAF[I]:
|
|
|
436
501
|
return acc
|
|
437
502
|
|
|
438
503
|
@overload
|
|
439
|
-
def foldr[R](self, f: Callable[[
|
|
504
|
+
def foldr[R](self, f: Callable[[X, X], X]) -> X: ...
|
|
440
505
|
@overload
|
|
441
|
-
def foldr[R](self, f: Callable[[
|
|
506
|
+
def foldr[R](self, f: Callable[[X, R], R], start: R) -> R: ...
|
|
507
|
+
|
|
508
|
+
def foldr[R](self, f: Callable[[X, R], R], start: R | NoValue = nada) -> R:
|
|
509
|
+
"""
|
|
510
|
+
.. admonition:: Fold right
|
|
442
511
|
|
|
443
|
-
|
|
444
|
-
"""Fold right with a function and an optional starting item.
|
|
512
|
+
Fold ``CAF`` right left with a function and optional starting item.
|
|
445
513
|
|
|
446
514
|
:param f: Folding function, second argument to ``f`` is for the accumulator.
|
|
447
515
|
:param start: Optional starting item.
|
|
448
516
|
:returns: Reduced value produced by the right fold.
|
|
449
|
-
:raises ValueError: When circular array empty and
|
|
517
|
+
:raises ValueError: When circular array empty and ``start`` not given.
|
|
518
|
+
|
|
450
519
|
"""
|
|
451
520
|
if self._cnt == 0:
|
|
452
521
|
if start is nada:
|
|
@@ -466,16 +535,26 @@ class CAF[I]:
|
|
|
466
535
|
return acc
|
|
467
536
|
|
|
468
537
|
def capacity(self) -> int:
|
|
469
|
-
"""
|
|
538
|
+
"""
|
|
539
|
+
.. admonition:: Get capacity
|
|
540
|
+
|
|
541
|
+
Get the fixed storage capacity of the circular array.
|
|
542
|
+
|
|
470
543
|
|
|
471
544
|
:returns: Fixed storage capacity.
|
|
545
|
+
|
|
472
546
|
"""
|
|
473
547
|
return self._cap
|
|
474
548
|
|
|
475
549
|
def empty(self) -> None:
|
|
476
|
-
"""
|
|
550
|
+
"""
|
|
551
|
+
.. admonition:: Empty circular array
|
|
552
|
+
|
|
553
|
+
Empty the circular array, keep current storage capacity.
|
|
554
|
+
|
|
555
|
+
"""
|
|
477
556
|
(
|
|
478
|
-
self.
|
|
557
|
+
self._xs,
|
|
479
558
|
self._front,
|
|
480
559
|
self._rear,
|
|
481
560
|
self._cnt,
|
|
@@ -487,18 +566,26 @@ class CAF[I]:
|
|
|
487
566
|
)
|
|
488
567
|
|
|
489
568
|
def fraction_filled(self) -> float:
|
|
490
|
-
"""
|
|
569
|
+
"""
|
|
570
|
+
.. admonition:: Get fraction filled
|
|
571
|
+
|
|
572
|
+
Find fraction of the storage capacity which is filled.
|
|
491
573
|
|
|
492
574
|
:returns: The ratio count/capacity.
|
|
575
|
+
|
|
493
576
|
"""
|
|
494
577
|
return self._cnt / self._cap
|
|
495
578
|
|
|
496
579
|
|
|
497
|
-
def caf[T](*
|
|
498
|
-
"""
|
|
580
|
+
def caf[T](*ts: T, cap: int = 2) -> CAF[T]:
|
|
581
|
+
"""
|
|
582
|
+
.. admonition:: Circular array factory function
|
|
583
|
+
|
|
584
|
+
Produce a circular array from a variable number of arguments.
|
|
499
585
|
|
|
500
|
-
:param
|
|
586
|
+
:param ts: Initial items for a new fixed capacity circular array.
|
|
501
587
|
:param cap: The minimum storage capacity to set.
|
|
502
588
|
:returns: New fixed storage capacity circular array.
|
|
589
|
+
|
|
503
590
|
"""
|
|
504
|
-
return CAF(
|
|
591
|
+
return CAF(ts, cap=cap)
|