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