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