pythonic-fp-circulararray 6.0.1__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 +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.2.dist-info}/METADATA +2 -2
- pythonic_fp_circulararray-6.0.2.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.2.dist-info}/WHEEL +0 -0
- {pythonic_fp_circulararray-6.0.1.dist-info → pythonic_fp_circulararray-6.0.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -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:: Variable storage capacity circular array
|
|
16
|
+
.. admonition:: Variable storage capacity circular array CA
|
|
17
17
|
|
|
18
18
|
- O(1) pops either end
|
|
19
19
|
- O(1) amortized pushes either end
|
|
@@ -35,25 +35,25 @@ __all__ = ['CA', 'ca']
|
|
|
35
35
|
nada: Final[NoValue] = NoValue()
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
class CA[
|
|
39
|
-
__slots__ = '
|
|
38
|
+
class CA[X]:
|
|
39
|
+
__slots__ = '_xs', '_cnt', '_cap', '_front', '_rear'
|
|
40
40
|
|
|
41
|
-
def __init__(self, *
|
|
41
|
+
def __init__(self, *xs: Iterable[X]) -> None:
|
|
42
42
|
"""
|
|
43
|
-
:param
|
|
44
|
-
|
|
45
|
-
:raises TypeError: When ``items[0]`` not iterable.
|
|
43
|
+
:param xs: Optionally takes a single iterable to initially populate the circular array.
|
|
44
|
+
:raises TypeError: When ``xs[0]`` not iterable.
|
|
46
45
|
:raises ValueError: If more than 1 iterable is given.
|
|
46
|
+
|
|
47
47
|
"""
|
|
48
|
-
if (size := len(
|
|
48
|
+
if (size := len(xs)) > 1:
|
|
49
49
|
msg = f'CA expects at most 1 argument, got {size}'
|
|
50
50
|
raise ValueError(msg)
|
|
51
51
|
if size:
|
|
52
|
-
values: list[
|
|
53
|
-
self.
|
|
52
|
+
values: list[X | NoValue] = list(cast(Iterable[X | NoValue], xs[0]))
|
|
53
|
+
self._xs = [nada] + values + [nada]
|
|
54
54
|
else:
|
|
55
|
-
self.
|
|
56
|
-
self._cap = (cap := len(self.
|
|
55
|
+
self._xs = [nada, nada]
|
|
56
|
+
self._cap = (cap := len(self._xs))
|
|
57
57
|
self._cnt = cap - 2
|
|
58
58
|
if cap == 2:
|
|
59
59
|
self._front = 0
|
|
@@ -65,21 +65,21 @@ class CA[I]:
|
|
|
65
65
|
def _double_storage_capacity(self) -> None:
|
|
66
66
|
if self._front <= self._rear:
|
|
67
67
|
(
|
|
68
|
-
self.
|
|
68
|
+
self._xs,
|
|
69
69
|
self._cap,
|
|
70
70
|
) = (
|
|
71
|
-
self.
|
|
71
|
+
self._xs + [nada] * self._cap,
|
|
72
72
|
self._cap * 2,
|
|
73
73
|
)
|
|
74
74
|
else:
|
|
75
75
|
(
|
|
76
|
-
self.
|
|
76
|
+
self._xs,
|
|
77
77
|
self._front,
|
|
78
78
|
self._cap,
|
|
79
79
|
) = (
|
|
80
|
-
self.
|
|
80
|
+
self._xs[: self._front]
|
|
81
81
|
+ [nada] * self._cap
|
|
82
|
-
+ self.
|
|
82
|
+
+ self._xs[self._front :],
|
|
83
83
|
self._front + self._cap,
|
|
84
84
|
2 * self._cap,
|
|
85
85
|
)
|
|
@@ -91,7 +91,7 @@ class CA[I]:
|
|
|
91
91
|
self._cap,
|
|
92
92
|
self._front,
|
|
93
93
|
self._rear,
|
|
94
|
-
self.
|
|
94
|
+
self._xs,
|
|
95
95
|
) = (
|
|
96
96
|
2,
|
|
97
97
|
0,
|
|
@@ -103,12 +103,12 @@ class CA[I]:
|
|
|
103
103
|
self._cap,
|
|
104
104
|
self._front,
|
|
105
105
|
self._rear,
|
|
106
|
-
self.
|
|
106
|
+
self._xs,
|
|
107
107
|
) = (
|
|
108
108
|
3,
|
|
109
109
|
1,
|
|
110
110
|
1,
|
|
111
|
-
[nada, self.
|
|
111
|
+
[nada, self._xs[self._front], nada],
|
|
112
112
|
)
|
|
113
113
|
case _:
|
|
114
114
|
if self._front <= self._rear:
|
|
@@ -116,30 +116,30 @@ class CA[I]:
|
|
|
116
116
|
self._cap,
|
|
117
117
|
self._front,
|
|
118
118
|
self._rear,
|
|
119
|
-
self.
|
|
119
|
+
self._xs,
|
|
120
120
|
) = (
|
|
121
121
|
self._cnt + 2,
|
|
122
122
|
1,
|
|
123
123
|
self._cnt,
|
|
124
|
-
[nada] + self.
|
|
124
|
+
[nada] + self._xs[self._front : self._rear + 1] + [nada],
|
|
125
125
|
)
|
|
126
126
|
else:
|
|
127
127
|
(
|
|
128
128
|
self._cap,
|
|
129
129
|
self._front,
|
|
130
130
|
self._rear,
|
|
131
|
-
self.
|
|
131
|
+
self._xs,
|
|
132
132
|
) = (
|
|
133
133
|
self._cnt + 2,
|
|
134
134
|
1,
|
|
135
135
|
self._cnt,
|
|
136
136
|
[nada]
|
|
137
|
-
+ self.
|
|
138
|
-
+ self.
|
|
137
|
+
+ self._xs[self._front :]
|
|
138
|
+
+ self._xs[: self._rear + 1]
|
|
139
139
|
+ [nada],
|
|
140
140
|
)
|
|
141
141
|
|
|
142
|
-
def __iter__(self) -> Iterator[
|
|
142
|
+
def __iter__(self) -> Iterator[X]:
|
|
143
143
|
if self._cnt > 0:
|
|
144
144
|
(
|
|
145
145
|
capacity,
|
|
@@ -150,15 +150,15 @@ class CA[I]:
|
|
|
150
150
|
self._cap,
|
|
151
151
|
self._rear,
|
|
152
152
|
self._front,
|
|
153
|
-
self.
|
|
153
|
+
self._xs.copy(),
|
|
154
154
|
)
|
|
155
155
|
|
|
156
156
|
while position != rear:
|
|
157
|
-
yield cast(
|
|
157
|
+
yield cast(X, current_state[position])
|
|
158
158
|
position = (position + 1) % capacity
|
|
159
|
-
yield cast(
|
|
159
|
+
yield cast(X, current_state[position])
|
|
160
160
|
|
|
161
|
-
def __reversed__(self) -> Iterator[
|
|
161
|
+
def __reversed__(self) -> Iterator[X]:
|
|
162
162
|
if self._cnt > 0:
|
|
163
163
|
(
|
|
164
164
|
capacity,
|
|
@@ -169,18 +169,26 @@ class CA[I]:
|
|
|
169
169
|
self._cap,
|
|
170
170
|
self._front,
|
|
171
171
|
self._rear,
|
|
172
|
-
self.
|
|
172
|
+
self._xs.copy(),
|
|
173
173
|
)
|
|
174
174
|
|
|
175
175
|
while position != front:
|
|
176
|
-
yield cast(
|
|
176
|
+
yield cast(X, current_state[position])
|
|
177
177
|
position = (position - 1) % capacity
|
|
178
|
-
yield cast(
|
|
178
|
+
yield cast(X, current_state[position])
|
|
179
179
|
|
|
180
180
|
def __repr__(self) -> str:
|
|
181
|
+
"""
|
|
182
|
+
:returns: String of the form ``ca(x1, x2, ..., xn)``.
|
|
183
|
+
|
|
184
|
+
"""
|
|
181
185
|
return 'ca(' + ', '.join(map(repr, self)) + ')'
|
|
182
186
|
|
|
183
187
|
def __str__(self) -> str:
|
|
188
|
+
"""
|
|
189
|
+
:returns: String of the form ``(|x1, x2, ..., xn|)``.
|
|
190
|
+
|
|
191
|
+
"""
|
|
184
192
|
return '(|' + ', '.join(map(str, self)) + '|)'
|
|
185
193
|
|
|
186
194
|
def __bool__(self) -> bool:
|
|
@@ -190,20 +198,20 @@ class CA[I]:
|
|
|
190
198
|
return self._cnt
|
|
191
199
|
|
|
192
200
|
@overload
|
|
193
|
-
def __getitem__(self, idx: int) ->
|
|
201
|
+
def __getitem__(self, idx: int) -> X: ...
|
|
194
202
|
@overload
|
|
195
|
-
def __getitem__(self, idx: slice) -> 'CA[
|
|
203
|
+
def __getitem__(self, idx: slice) -> 'CA[X]': ...
|
|
196
204
|
|
|
197
|
-
def __getitem__(self, idx: int | slice) ->
|
|
205
|
+
def __getitem__(self, idx: int | slice) -> X | 'CA[X]':
|
|
198
206
|
if isinstance(idx, slice):
|
|
199
207
|
return CA(list(self)[idx])
|
|
200
208
|
|
|
201
209
|
cnt = self._cnt
|
|
202
210
|
if 0 <= idx < cnt:
|
|
203
|
-
return cast(
|
|
211
|
+
return cast(X, self._xs[(self._front + idx) % self._cap])
|
|
204
212
|
|
|
205
213
|
if -cnt <= idx < 0:
|
|
206
|
-
return cast(
|
|
214
|
+
return cast(X, self._xs[(self._front + cnt + idx) % self._cap])
|
|
207
215
|
|
|
208
216
|
if cnt == 0:
|
|
209
217
|
msg0 = 'Trying to get a value from an empty CA.'
|
|
@@ -215,24 +223,24 @@ class CA[I]:
|
|
|
215
223
|
raise IndexError(msg1 + msg2 + msg3)
|
|
216
224
|
|
|
217
225
|
@overload
|
|
218
|
-
def __setitem__(self, idx: int, vals:
|
|
226
|
+
def __setitem__(self, idx: int, vals: X) -> None: ...
|
|
219
227
|
@overload
|
|
220
|
-
def __setitem__(self, idx: slice, vals: Iterable[
|
|
228
|
+
def __setitem__(self, idx: slice, vals: Iterable[X]) -> None: ...
|
|
221
229
|
|
|
222
|
-
def __setitem__(self, idx: int | slice, vals:
|
|
230
|
+
def __setitem__(self, idx: int | slice, vals: X | Iterable[X]) -> None:
|
|
223
231
|
if isinstance(idx, slice):
|
|
224
232
|
if isinstance(vals, Iterable):
|
|
225
233
|
item_list = list(self)
|
|
226
234
|
item_list[idx] = vals
|
|
227
235
|
_ca = CA(item_list)
|
|
228
236
|
(
|
|
229
|
-
self.
|
|
237
|
+
self._xs,
|
|
230
238
|
self._cnt,
|
|
231
239
|
self._cap,
|
|
232
240
|
self._front,
|
|
233
241
|
self._rear,
|
|
234
242
|
) = (
|
|
235
|
-
_ca.
|
|
243
|
+
_ca._xs,
|
|
236
244
|
_ca._cnt,
|
|
237
245
|
_ca._cap,
|
|
238
246
|
_ca._front,
|
|
@@ -245,9 +253,9 @@ class CA[I]:
|
|
|
245
253
|
|
|
246
254
|
cnt = self._cnt
|
|
247
255
|
if 0 <= idx < cnt:
|
|
248
|
-
self.
|
|
256
|
+
self._xs[(self._front + idx) % self._cap] = cast(X, vals)
|
|
249
257
|
elif -cnt <= idx < 0:
|
|
250
|
-
self.
|
|
258
|
+
self._xs[(self._front + cnt + idx) % self._cap] = cast(X, vals)
|
|
251
259
|
else:
|
|
252
260
|
if cnt < 1:
|
|
253
261
|
msg0 = 'Trying to index into an empty CA.'
|
|
@@ -267,13 +275,13 @@ class CA[I]:
|
|
|
267
275
|
del item_list[idx]
|
|
268
276
|
_ca = CA(item_list)
|
|
269
277
|
(
|
|
270
|
-
self.
|
|
278
|
+
self._xs,
|
|
271
279
|
self._cnt,
|
|
272
280
|
self._cap,
|
|
273
281
|
self._front,
|
|
274
282
|
self._rear,
|
|
275
283
|
) = (
|
|
276
|
-
_ca.
|
|
284
|
+
_ca._xs,
|
|
277
285
|
_ca._cnt,
|
|
278
286
|
_ca._cap,
|
|
279
287
|
_ca._front,
|
|
@@ -284,9 +292,10 @@ class CA[I]:
|
|
|
284
292
|
def __eq__(self, other: object) -> bool:
|
|
285
293
|
"""
|
|
286
294
|
:param other: The object to be compared to.
|
|
287
|
-
:returns: ``True`` if object is another CA whose items compare
|
|
288
|
-
as equal to the corresponding items in the CA
|
|
295
|
+
:returns: ``True`` if object is another ``CA`` whose items compare
|
|
296
|
+
as equal to the corresponding items in the ``CA``,
|
|
289
297
|
otherwise ``False``.
|
|
298
|
+
|
|
290
299
|
"""
|
|
291
300
|
if self is other:
|
|
292
301
|
return True
|
|
@@ -314,28 +323,33 @@ class CA[I]:
|
|
|
314
323
|
|
|
315
324
|
for nn in range(cnt1):
|
|
316
325
|
if (
|
|
317
|
-
self.
|
|
318
|
-
is other.
|
|
326
|
+
self._xs[(front1 + nn) % capacity1]
|
|
327
|
+
is other._xs[(front2 + nn) % capacity2]
|
|
319
328
|
):
|
|
320
329
|
continue
|
|
321
330
|
if (
|
|
322
|
-
self.
|
|
323
|
-
!= other.
|
|
331
|
+
self._xs[(front1 + nn) % capacity1]
|
|
332
|
+
!= other._xs[(front2 + nn) % capacity2]
|
|
324
333
|
):
|
|
325
334
|
return False
|
|
326
335
|
return True
|
|
327
336
|
|
|
328
|
-
def pushl(self, *
|
|
329
|
-
"""
|
|
337
|
+
def pushl(self, *xs: X) -> None:
|
|
338
|
+
"""
|
|
339
|
+
.. admonition:: Push left
|
|
340
|
+
|
|
341
|
+
Push items from the left onto the ``CA`` in the
|
|
342
|
+
order they were iterated.
|
|
343
|
+
|
|
344
|
+
:param xs: Items to be pushed onto the front of the circular array from the left.
|
|
330
345
|
|
|
331
|
-
:param items: Items pushed onto circular array from left (front).
|
|
332
346
|
"""
|
|
333
|
-
for item in
|
|
347
|
+
for item in xs:
|
|
334
348
|
if self._cnt == self._cap:
|
|
335
349
|
self._double_storage_capacity()
|
|
336
350
|
(
|
|
337
351
|
self._front,
|
|
338
|
-
self.
|
|
352
|
+
self._xs[self._front],
|
|
339
353
|
self._cnt,
|
|
340
354
|
) = (
|
|
341
355
|
(self._front - 1) % self._cap,
|
|
@@ -343,17 +357,22 @@ class CA[I]:
|
|
|
343
357
|
self._cnt + 1,
|
|
344
358
|
)
|
|
345
359
|
|
|
346
|
-
def pushr(self, *
|
|
347
|
-
"""
|
|
360
|
+
def pushr(self, *xs: X) -> None:
|
|
361
|
+
"""
|
|
362
|
+
.. admonition:: Push right
|
|
363
|
+
|
|
364
|
+
Push items from the right onto the ``CA`` in the
|
|
365
|
+
order they were iterated.
|
|
366
|
+
|
|
367
|
+
:param xs: Items to be pushed onto the rear of the ``CA`` from the right.
|
|
348
368
|
|
|
349
|
-
:param items: Items pushed onto circular array from right (rear).
|
|
350
369
|
"""
|
|
351
|
-
for item in
|
|
370
|
+
for item in xs:
|
|
352
371
|
if self._cnt == self._cap:
|
|
353
372
|
self._double_storage_capacity()
|
|
354
373
|
(
|
|
355
374
|
self._rear,
|
|
356
|
-
self.
|
|
375
|
+
self._xs[self._rear],
|
|
357
376
|
self._cnt,
|
|
358
377
|
) = (
|
|
359
378
|
(self._rear + 1) % self._cap,
|
|
@@ -361,20 +380,24 @@ class CA[I]:
|
|
|
361
380
|
self._cnt + 1,
|
|
362
381
|
)
|
|
363
382
|
|
|
364
|
-
def popl(self) ->
|
|
365
|
-
"""
|
|
383
|
+
def popl(self) -> X:
|
|
384
|
+
"""
|
|
385
|
+
.. admonition:: Pop left
|
|
386
|
+
|
|
387
|
+
Pop a single items off the left side of the ``CA``.
|
|
366
388
|
|
|
367
389
|
:returns: Item popped from left side (front) of circular array.
|
|
368
390
|
:raises ValueError: When called on an empty circular array.
|
|
391
|
+
|
|
369
392
|
"""
|
|
370
393
|
if self._cnt > 1:
|
|
371
394
|
(
|
|
372
395
|
d,
|
|
373
|
-
self.
|
|
396
|
+
self._xs[self._front],
|
|
374
397
|
self._front,
|
|
375
398
|
self._cnt,
|
|
376
399
|
) = (
|
|
377
|
-
self.
|
|
400
|
+
self._xs[self._front],
|
|
378
401
|
nada,
|
|
379
402
|
(self._front + 1) % self._cap,
|
|
380
403
|
self._cnt - 1,
|
|
@@ -382,12 +405,12 @@ class CA[I]:
|
|
|
382
405
|
elif self._cnt == 1:
|
|
383
406
|
(
|
|
384
407
|
d,
|
|
385
|
-
self.
|
|
408
|
+
self._xs[self._front],
|
|
386
409
|
self._cnt,
|
|
387
410
|
self._front,
|
|
388
411
|
self._rear,
|
|
389
412
|
) = (
|
|
390
|
-
self.
|
|
413
|
+
self._xs[self._front],
|
|
391
414
|
nada,
|
|
392
415
|
0,
|
|
393
416
|
0,
|
|
@@ -396,22 +419,26 @@ class CA[I]:
|
|
|
396
419
|
else:
|
|
397
420
|
msg = 'Method popl called on an empty CA'
|
|
398
421
|
raise ValueError(msg)
|
|
399
|
-
return cast(
|
|
422
|
+
return cast(X, d)
|
|
423
|
+
|
|
424
|
+
def popr(self) -> X:
|
|
425
|
+
"""
|
|
426
|
+
.. admonition:: Pop right
|
|
400
427
|
|
|
401
|
-
|
|
402
|
-
"""Pop single item off from right.
|
|
428
|
+
Pop a single items off the right side of the ``CA``.
|
|
403
429
|
|
|
404
430
|
:returns: Item popped from right side (rear) of circular array.
|
|
405
431
|
:raises ValueError: When called on an empty circular array.
|
|
432
|
+
|
|
406
433
|
"""
|
|
407
434
|
if self._cnt > 1:
|
|
408
435
|
(
|
|
409
436
|
d,
|
|
410
|
-
self.
|
|
437
|
+
self._xs[self._rear],
|
|
411
438
|
self._rear,
|
|
412
439
|
self._cnt,
|
|
413
440
|
) = (
|
|
414
|
-
self.
|
|
441
|
+
self._xs[self._rear],
|
|
415
442
|
nada,
|
|
416
443
|
(self._rear - 1) % self._cap,
|
|
417
444
|
self._cnt - 1,
|
|
@@ -419,12 +446,12 @@ class CA[I]:
|
|
|
419
446
|
elif self._cnt == 1:
|
|
420
447
|
(
|
|
421
448
|
d,
|
|
422
|
-
self.
|
|
449
|
+
self._xs[self._front],
|
|
423
450
|
self._cnt,
|
|
424
451
|
self._front,
|
|
425
452
|
self._rear,
|
|
426
453
|
) = (
|
|
427
|
-
self.
|
|
454
|
+
self._xs[self._front],
|
|
428
455
|
nada,
|
|
429
456
|
0,
|
|
430
457
|
0,
|
|
@@ -433,40 +460,53 @@ class CA[I]:
|
|
|
433
460
|
else:
|
|
434
461
|
msg = 'Method popr called on an empty CA'
|
|
435
462
|
raise ValueError(msg)
|
|
436
|
-
return cast(
|
|
463
|
+
return cast(X, d)
|
|
437
464
|
|
|
438
|
-
def popld(self, default:
|
|
439
|
-
"""
|
|
440
|
-
|
|
465
|
+
def popld(self, default: X) -> X:
|
|
466
|
+
"""
|
|
467
|
+
.. admonition:: Pop Left with default
|
|
468
|
+
|
|
469
|
+
Pop a single items off the left side of the ``CA``.
|
|
470
|
+
|
|
471
|
+
:param default: Default value to return if ``CA`` is empty.
|
|
472
|
+
:returns: Item popped from left side (front) of circular array
|
|
473
|
+
if not empty, otherwise return the provided default
|
|
474
|
+
value.
|
|
441
475
|
|
|
442
|
-
:param default: Item returned if circular array is empty.
|
|
443
|
-
:returns: Item popped from left side or default item if empty.
|
|
444
476
|
"""
|
|
445
477
|
try:
|
|
446
478
|
return self.popl()
|
|
447
479
|
except ValueError:
|
|
448
480
|
return default
|
|
449
481
|
|
|
450
|
-
def poprd(self, default:
|
|
451
|
-
"""
|
|
452
|
-
|
|
482
|
+
def poprd(self, default: X) -> X:
|
|
483
|
+
"""
|
|
484
|
+
.. admonition:: Pop Right with default
|
|
485
|
+
|
|
486
|
+
Pop a single items off the right side of the ``CA``.
|
|
487
|
+
|
|
488
|
+
:param default: Default value to return if ``CA`` is empty.
|
|
489
|
+
:returns: Item popped from right side (rear) of circular array
|
|
490
|
+
if not empty, otherwise return the provided default
|
|
491
|
+
value.
|
|
453
492
|
|
|
454
|
-
:param default: Item returned if circular array is empty.
|
|
455
|
-
:returns: Item popped from right side or default item if empty.
|
|
456
493
|
"""
|
|
457
494
|
try:
|
|
458
495
|
return self.popr()
|
|
459
496
|
except ValueError:
|
|
460
497
|
return default
|
|
461
498
|
|
|
462
|
-
def poplt(self, maximum: int) -> tuple[
|
|
463
|
-
"""
|
|
499
|
+
def poplt(self, maximum: int) -> tuple[X, ...]:
|
|
500
|
+
"""
|
|
501
|
+
.. admonition:: Pop multiple items from left
|
|
502
|
+
|
|
503
|
+
Pop items off the left side of the ``CA``.
|
|
504
|
+
|
|
505
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items in ``CA``.
|
|
506
|
+
:returns: A ``tuple`` of the items popped, left to right.
|
|
464
507
|
|
|
465
|
-
:param maximum: Maximum number of items to pop, may pop less
|
|
466
|
-
if not enough items.
|
|
467
|
-
:returns: Tuple of items in the order popped, left to right.
|
|
468
508
|
"""
|
|
469
|
-
item_list: list[
|
|
509
|
+
item_list: list[X] = []
|
|
470
510
|
|
|
471
511
|
while maximum > 0:
|
|
472
512
|
try:
|
|
@@ -478,14 +518,17 @@ class CA[I]:
|
|
|
478
518
|
|
|
479
519
|
return tuple(item_list)
|
|
480
520
|
|
|
481
|
-
def poprt(self, maximum: int) -> tuple[
|
|
482
|
-
"""
|
|
521
|
+
def poprt(self, maximum: int) -> tuple[X, ...]:
|
|
522
|
+
"""
|
|
523
|
+
.. admonition:: Pop multiple items from right
|
|
524
|
+
|
|
525
|
+
Pop items off the right side of the ``CA``.
|
|
526
|
+
|
|
527
|
+
:param maximum: Maximum number of items to pop, may pop less if not enough items in ``CA``.
|
|
528
|
+
:returns: A ``tuple`` of the items popped, right to left.
|
|
483
529
|
|
|
484
|
-
:param maximum: Maximum number of items to pop, may pop less
|
|
485
|
-
if not enough items.
|
|
486
|
-
:returns: Tuple of items in the order popped, right to left.
|
|
487
530
|
"""
|
|
488
|
-
item_list: list[
|
|
531
|
+
item_list: list[X] = []
|
|
489
532
|
while maximum > 0:
|
|
490
533
|
try:
|
|
491
534
|
item_list.append(self.popr())
|
|
@@ -496,9 +539,14 @@ class CA[I]:
|
|
|
496
539
|
return tuple(item_list)
|
|
497
540
|
|
|
498
541
|
def rotl(self, n: int = 1) -> None:
|
|
499
|
-
"""
|
|
542
|
+
"""
|
|
543
|
+
.. admonition:: Rotate left
|
|
544
|
+
|
|
545
|
+
Rotate contents of ``CA`` to the left putting first
|
|
546
|
+
item onto rear.
|
|
547
|
+
|
|
548
|
+
:param n: Number of times to shift items left. Default 1 time.
|
|
500
549
|
|
|
501
|
-
:param n: Number of times to shift elements to the left.
|
|
502
550
|
"""
|
|
503
551
|
if self._cnt < 2:
|
|
504
552
|
return
|
|
@@ -506,37 +554,48 @@ class CA[I]:
|
|
|
506
554
|
self.pushr(self.popl())
|
|
507
555
|
|
|
508
556
|
def rotr(self, n: int = 1) -> None:
|
|
509
|
-
"""
|
|
557
|
+
"""
|
|
558
|
+
.. admonition:: Rotate right
|
|
559
|
+
|
|
560
|
+
Rotate contents of ``CA`` to the right putting last
|
|
561
|
+
item onto front.
|
|
562
|
+
|
|
563
|
+
:param n: Number of times to shift items right. Default 1 time.
|
|
510
564
|
|
|
511
|
-
:param n: Number of times to shift elements to the right.
|
|
512
565
|
"""
|
|
513
566
|
if self._cnt < 2:
|
|
514
567
|
return
|
|
515
568
|
for _ in range(n, 0, -1):
|
|
516
569
|
self.pushl(self.popr())
|
|
517
570
|
|
|
518
|
-
def map[
|
|
519
|
-
"""
|
|
571
|
+
def map[Y](self, f: Callable[[X], Y]) -> 'CA[Y]':
|
|
572
|
+
"""
|
|
573
|
+
.. admonition:: Map function over the CA
|
|
574
|
+
|
|
575
|
+
Apply function ``f`` over the circular array's contents.
|
|
520
576
|
|
|
521
|
-
:param f: Callable from type ``
|
|
577
|
+
:param f: Callable from type ``X`` to type ``Y``.
|
|
522
578
|
:returns: New auto-resizing circular array instance.
|
|
579
|
+
|
|
523
580
|
"""
|
|
524
581
|
return CA(map(f, self))
|
|
525
582
|
|
|
526
583
|
@overload
|
|
527
|
-
def foldl[L](self, f: Callable[[
|
|
584
|
+
def foldl[L](self, f: Callable[[X, X], X]) -> X: ...
|
|
528
585
|
@overload
|
|
529
|
-
def foldl[L](self, f: Callable[[L,
|
|
586
|
+
def foldl[L](self, f: Callable[[L, X], L], start: L) -> L: ...
|
|
587
|
+
|
|
588
|
+
def foldl[L](self, f: Callable[[L, X], L], start: L | NoValue = NoValue()) -> L:
|
|
589
|
+
"""
|
|
590
|
+
.. admonition:: Fold left
|
|
530
591
|
|
|
531
|
-
|
|
532
|
-
"""Fold left with a function and optional starting item.
|
|
592
|
+
Fold ``CA`` left with a function and optional starting item.
|
|
533
593
|
|
|
534
|
-
:param f: Folding function, first argument to ``f`` is for
|
|
535
|
-
|
|
536
|
-
:param start: "Optional" starting item.
|
|
594
|
+
:param f: Folding function, first argument to ``f`` is for the accumulator.
|
|
595
|
+
:param start: Optional starting item.
|
|
537
596
|
:returns: Reduced value produced by the left fold.
|
|
538
|
-
:raises ValueError: When circular array empty and
|
|
539
|
-
|
|
597
|
+
:raises ValueError: When circular array empty and ``start`` not given.
|
|
598
|
+
|
|
540
599
|
"""
|
|
541
600
|
if self._cnt == 0:
|
|
542
601
|
if start is nada:
|
|
@@ -556,19 +615,21 @@ class CA[I]:
|
|
|
556
615
|
return acc
|
|
557
616
|
|
|
558
617
|
@overload
|
|
559
|
-
def foldr[R](self, f: Callable[[
|
|
618
|
+
def foldr[R](self, f: Callable[[X, X], X]) -> X: ...
|
|
560
619
|
@overload
|
|
561
|
-
def foldr[R](self, f: Callable[[
|
|
620
|
+
def foldr[R](self, f: Callable[[X, R], R], start: R) -> R: ...
|
|
621
|
+
|
|
622
|
+
def foldr[R](self, f: Callable[[X, R], R], start: R | NoValue = nada) -> R:
|
|
623
|
+
"""
|
|
624
|
+
.. admonition:: Fold right
|
|
562
625
|
|
|
563
|
-
|
|
564
|
-
"""Fold right with a function and an optional starting item.
|
|
626
|
+
Fold ``CA`` right with a function and optional starting item.
|
|
565
627
|
|
|
566
|
-
:param f: Folding function, second argument to ``f`` is for
|
|
567
|
-
the accumulator.
|
|
628
|
+
:param f: Folding function, second argument to ``f`` is for the accumulator.
|
|
568
629
|
:param start: Optional starting item.
|
|
569
630
|
:returns: Reduced value produced by the right fold.
|
|
570
|
-
:raises ValueError: When circular array empty and
|
|
571
|
-
|
|
631
|
+
:raises ValueError: When circular array empty and ``start`` not given.
|
|
632
|
+
|
|
572
633
|
"""
|
|
573
634
|
if self._cnt == 0:
|
|
574
635
|
if start is nada:
|
|
@@ -588,16 +649,25 @@ class CA[I]:
|
|
|
588
649
|
return acc
|
|
589
650
|
|
|
590
651
|
def capacity(self) -> int:
|
|
591
|
-
"""
|
|
652
|
+
"""
|
|
653
|
+
.. admonition:: Get capacity
|
|
654
|
+
|
|
655
|
+
Get the current storage capacity of the circular array.
|
|
592
656
|
|
|
593
657
|
:returns: Current storage capacity.
|
|
658
|
+
|
|
594
659
|
"""
|
|
595
660
|
return self._cap
|
|
596
661
|
|
|
597
662
|
def empty(self) -> None:
|
|
598
|
-
"""
|
|
663
|
+
"""
|
|
664
|
+
.. admonition:: Empty circular array
|
|
665
|
+
|
|
666
|
+
Empty the circular array, keep current storage capacity.
|
|
667
|
+
|
|
668
|
+
"""
|
|
599
669
|
(
|
|
600
|
-
self.
|
|
670
|
+
self._xs,
|
|
601
671
|
self._front,
|
|
602
672
|
self._rear,
|
|
603
673
|
self._cnt,
|
|
@@ -609,37 +679,48 @@ class CA[I]:
|
|
|
609
679
|
)
|
|
610
680
|
|
|
611
681
|
def fraction_filled(self) -> float:
|
|
612
|
-
"""
|
|
682
|
+
"""
|
|
683
|
+
.. admonition:: Get fraction filled
|
|
684
|
+
|
|
685
|
+
Find fraction of the storage capacity which is filled.
|
|
613
686
|
|
|
614
687
|
:returns: The ratio count/capacity.
|
|
688
|
+
|
|
615
689
|
"""
|
|
616
690
|
return self._cnt / self._cap
|
|
617
691
|
|
|
618
692
|
def resize(self, minimum_capacity: int = 2) -> None:
|
|
619
|
-
"""
|
|
620
|
-
|
|
621
|
-
|
|
693
|
+
"""
|
|
694
|
+
.. admonition:: Resize
|
|
695
|
+
|
|
696
|
+
Compact circular array and, if necessary, resize to a
|
|
697
|
+
minimum storage capacity. To just compact the circular
|
|
698
|
+
array, do not provide ``minimum_capacity``.
|
|
699
|
+
|
|
700
|
+
:param minimum_capacity: Minimum storage capacity to compact the circular array.
|
|
622
701
|
|
|
623
|
-
:param minimum_capacity: Minimum storage capacity to compact
|
|
624
|
-
the circular array.
|
|
625
702
|
"""
|
|
626
703
|
self._compact_storage_capacity()
|
|
627
704
|
if (min_cap := minimum_capacity) > self._cap:
|
|
628
705
|
(
|
|
629
706
|
self._cap,
|
|
630
|
-
self.
|
|
707
|
+
self._xs,
|
|
631
708
|
) = (
|
|
632
709
|
min_cap,
|
|
633
|
-
self.
|
|
710
|
+
self._xs + [nada] * (min_cap - self._cap),
|
|
634
711
|
)
|
|
635
712
|
if self._cnt == 0:
|
|
636
713
|
self._front, self._rear = 0, self._cap - 1
|
|
637
714
|
|
|
638
715
|
|
|
639
|
-
def ca[T](*
|
|
640
|
-
"""
|
|
716
|
+
def ca[T](*ts: T) -> CA[T]:
|
|
717
|
+
"""
|
|
718
|
+
.. admonition:: Circular array factory function
|
|
719
|
+
|
|
720
|
+
Produce a circular array from a variable number of arguments.
|
|
641
721
|
|
|
642
|
-
:param
|
|
722
|
+
:param ts: Initial items for a new auto-resizing circular array.
|
|
643
723
|
:returns: New variable storage capacity circular array.
|
|
724
|
+
|
|
644
725
|
"""
|
|
645
|
-
return CA(
|
|
726
|
+
return CA(ts)
|