pythonic-fp-circulararray 5.3.3__py3-none-any.whl → 5.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonic_fp/circulararray/auto.py +226 -199
- pythonic_fp/circulararray/auto.pyi +12 -3
- pythonic_fp/circulararray/fixed.py +157 -132
- pythonic_fp/circulararray/fixed.pyi +15 -3
- {pythonic_fp_circulararray-5.3.3.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/METADATA +27 -12
- pythonic_fp_circulararray-5.4.0.dist-info/RECORD +11 -0
- pythonic_fp_circulararray-5.3.3.dist-info/RECORD +0 -11
- {pythonic_fp_circulararray-5.3.3.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_circulararray-5.3.3.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,38 +18,44 @@ Variable Storage Capacity
|
|
|
18
18
|
|
|
19
19
|
**Circular array with variable storage capacity.**
|
|
20
20
|
|
|
21
|
-
- O(1) pops either end
|
|
22
|
-
- O(1) amortized pushes either end
|
|
21
|
+
- O(1) pops either end
|
|
22
|
+
- O(1) amortized pushes either end
|
|
23
23
|
- O(1) indexing, fully supports slicing
|
|
24
24
|
- auto-resizing more storage capacity when necessary, manually compatible
|
|
25
|
-
- iterable,
|
|
25
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
26
26
|
- comparisons compare identity before equality, like builtins
|
|
27
27
|
- in boolean context, falsy when empty, otherwise truthy
|
|
28
|
-
-
|
|
28
|
+
- function ``ca`` produces auto-resizing circular array from arguments
|
|
29
29
|
|
|
30
30
|
"""
|
|
31
|
+
|
|
31
32
|
from collections.abc import Callable, Iterable, Iterator
|
|
32
|
-
from typing import cast, overload
|
|
33
|
+
from typing import cast, Final, overload
|
|
34
|
+
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
33
35
|
|
|
34
36
|
__all__ = ['CA', 'ca']
|
|
35
37
|
|
|
38
|
+
nada: Final[NoValue] = NoValue()
|
|
36
39
|
|
|
37
|
-
class CA[I]():
|
|
38
40
|
|
|
41
|
+
class CA[I]:
|
|
39
42
|
__slots__ = '_items', '_cnt', '_cap', '_front', '_rear'
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
@overload
|
|
45
|
+
def __init__(self) -> None: ...
|
|
46
|
+
@overload
|
|
47
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
48
|
+
|
|
49
|
+
def __init__(self, items: Iterable[I | NoValue] | NoValue = nada) -> None:
|
|
45
50
|
"""
|
|
46
|
-
:param items: Optional iterable to initial populate circular array.
|
|
51
|
+
:param items: "Optional" iterable to initial populate circular array.
|
|
47
52
|
:raises TypeError: When ``items`` not Iterable.
|
|
48
53
|
"""
|
|
49
|
-
if items is
|
|
50
|
-
self._items: list[I |
|
|
54
|
+
if items is nada:
|
|
55
|
+
self._items: list[I | NoValue] = [nada, nada]
|
|
51
56
|
else:
|
|
52
|
-
|
|
57
|
+
values: list[I | NoValue] = list(cast(Iterable[I | NoValue], items))
|
|
58
|
+
self._items = [nada] + values + [nada]
|
|
53
59
|
self._cap = cap = len(self._items)
|
|
54
60
|
self._cnt = cap - 2
|
|
55
61
|
if cap == 2:
|
|
@@ -62,88 +68,93 @@ class CA[I]():
|
|
|
62
68
|
def _double_storage_capacity(self) -> None:
|
|
63
69
|
if self._front <= self._rear:
|
|
64
70
|
(
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
self._items,
|
|
72
|
+
self._cap,
|
|
67
73
|
) = (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
self._items + [nada] * self._cap,
|
|
75
|
+
self._cap * 2,
|
|
76
|
+
)
|
|
71
77
|
else:
|
|
72
78
|
(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
self._items,
|
|
80
|
+
self._front,
|
|
81
|
+
self._cap,
|
|
76
82
|
) = (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
self._items[: self._front]
|
|
84
|
+
+ [nada] * self._cap
|
|
85
|
+
+ self._items[self._front :],
|
|
86
|
+
self._front + self._cap,
|
|
87
|
+
2 * self._cap,
|
|
88
|
+
)
|
|
81
89
|
|
|
82
90
|
def _compact_storage_capacity(self) -> None:
|
|
83
91
|
match self._cnt:
|
|
84
92
|
case 0:
|
|
85
93
|
(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
self._cap,
|
|
95
|
+
self._front,
|
|
96
|
+
self._rear,
|
|
97
|
+
self._items,
|
|
90
98
|
) = (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
2,
|
|
100
|
+
0,
|
|
101
|
+
1,
|
|
102
|
+
[nada, nada],
|
|
103
|
+
)
|
|
96
104
|
case 1:
|
|
97
105
|
(
|
|
106
|
+
self._cap,
|
|
107
|
+
self._front,
|
|
108
|
+
self._rear,
|
|
109
|
+
self._items,
|
|
110
|
+
) = (
|
|
111
|
+
3,
|
|
112
|
+
1,
|
|
113
|
+
1,
|
|
114
|
+
[nada, self._items[self._front], nada],
|
|
115
|
+
)
|
|
116
|
+
case _:
|
|
117
|
+
if self._front <= self._rear:
|
|
118
|
+
(
|
|
98
119
|
self._cap,
|
|
99
120
|
self._front,
|
|
100
121
|
self._rear,
|
|
101
122
|
self._items,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
1,
|
|
123
|
+
) = (
|
|
124
|
+
self._cnt + 2,
|
|
105
125
|
1,
|
|
106
|
-
|
|
126
|
+
self._cnt,
|
|
127
|
+
[nada] + self._items[self._front : self._rear + 1] + [nada],
|
|
107
128
|
)
|
|
108
|
-
case _:
|
|
109
|
-
if self._front <= self._rear:
|
|
110
|
-
(
|
|
111
|
-
self._cap,
|
|
112
|
-
self._front,
|
|
113
|
-
self._rear,
|
|
114
|
-
self._items,
|
|
115
|
-
) = (
|
|
116
|
-
self._cnt + 2,
|
|
117
|
-
1,
|
|
118
|
-
self._cnt,
|
|
119
|
-
[None] + self._items[self._front : self._rear + 1] + [None],
|
|
120
|
-
)
|
|
121
129
|
else:
|
|
122
130
|
(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
self._cap,
|
|
132
|
+
self._front,
|
|
133
|
+
self._rear,
|
|
134
|
+
self._items,
|
|
127
135
|
) = (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
self._cnt + 2,
|
|
137
|
+
1,
|
|
138
|
+
self._cnt,
|
|
139
|
+
[nada]
|
|
140
|
+
+ self._items[self._front :]
|
|
141
|
+
+ self._items[: self._rear + 1]
|
|
142
|
+
+ [nada],
|
|
143
|
+
)
|
|
133
144
|
|
|
134
145
|
def __iter__(self) -> Iterator[I]:
|
|
135
146
|
if self._cnt > 0:
|
|
136
147
|
(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
148
|
+
capacity,
|
|
149
|
+
rear,
|
|
150
|
+
position,
|
|
151
|
+
current_state,
|
|
141
152
|
) = (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
self._cap,
|
|
154
|
+
self._rear,
|
|
155
|
+
self._front,
|
|
156
|
+
self._items.copy(),
|
|
157
|
+
)
|
|
147
158
|
|
|
148
159
|
while position != rear:
|
|
149
160
|
yield cast(I, current_state[position])
|
|
@@ -153,16 +164,16 @@ class CA[I]():
|
|
|
153
164
|
def __reversed__(self) -> Iterator[I]:
|
|
154
165
|
if self._cnt > 0:
|
|
155
166
|
(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
capacity,
|
|
168
|
+
front,
|
|
169
|
+
position,
|
|
170
|
+
current_state,
|
|
160
171
|
) = (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
172
|
+
self._cap,
|
|
173
|
+
self._front,
|
|
174
|
+
self._rear,
|
|
175
|
+
self._items.copy(),
|
|
176
|
+
)
|
|
166
177
|
|
|
167
178
|
while position != front:
|
|
168
179
|
yield cast(I, current_state[position])
|
|
@@ -184,9 +195,9 @@ class CA[I]():
|
|
|
184
195
|
@overload
|
|
185
196
|
def __getitem__(self, idx: int) -> I: ...
|
|
186
197
|
@overload
|
|
187
|
-
def __getitem__(self, idx: slice) ->
|
|
198
|
+
def __getitem__(self, idx: slice) -> 'CA[I]': ...
|
|
188
199
|
|
|
189
|
-
def __getitem__(self, idx: int | slice) -> I |
|
|
200
|
+
def __getitem__(self, idx: int | slice) -> I | 'CA[I]':
|
|
190
201
|
if isinstance(idx, slice):
|
|
191
202
|
return CA(list(self)[idx])
|
|
192
203
|
|
|
@@ -218,18 +229,18 @@ class CA[I]():
|
|
|
218
229
|
item_list[idx] = vals
|
|
219
230
|
_ca = CA(item_list)
|
|
220
231
|
(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
232
|
+
self._items,
|
|
233
|
+
self._cnt,
|
|
234
|
+
self._cap,
|
|
235
|
+
self._front,
|
|
236
|
+
self._rear,
|
|
226
237
|
) = (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
238
|
+
_ca._items,
|
|
239
|
+
_ca._cnt,
|
|
240
|
+
_ca._cap,
|
|
241
|
+
_ca._front,
|
|
242
|
+
_ca._rear,
|
|
243
|
+
)
|
|
233
244
|
return
|
|
234
245
|
|
|
235
246
|
msg = 'must assign iterable to extended slice'
|
|
@@ -259,18 +270,18 @@ class CA[I]():
|
|
|
259
270
|
del item_list[idx]
|
|
260
271
|
_ca = CA(item_list)
|
|
261
272
|
(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
273
|
+
self._items,
|
|
274
|
+
self._cnt,
|
|
275
|
+
self._cap,
|
|
276
|
+
self._front,
|
|
277
|
+
self._rear,
|
|
267
278
|
) = (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
279
|
+
_ca._items,
|
|
280
|
+
_ca._cnt,
|
|
281
|
+
_ca._cap,
|
|
282
|
+
_ca._front,
|
|
283
|
+
_ca._rear,
|
|
284
|
+
)
|
|
274
285
|
del _ca
|
|
275
286
|
|
|
276
287
|
def __eq__(self, other: object) -> bool:
|
|
@@ -280,28 +291,34 @@ class CA[I]():
|
|
|
280
291
|
return False
|
|
281
292
|
|
|
282
293
|
(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
294
|
+
front1,
|
|
295
|
+
count1,
|
|
296
|
+
capacity1,
|
|
297
|
+
front2,
|
|
298
|
+
count2,
|
|
299
|
+
capacity2,
|
|
289
300
|
) = (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
301
|
+
self._front,
|
|
302
|
+
self._cnt,
|
|
303
|
+
self._cap,
|
|
304
|
+
other._front,
|
|
305
|
+
other._cnt,
|
|
306
|
+
other._cap,
|
|
307
|
+
)
|
|
297
308
|
|
|
298
309
|
if count1 != count2:
|
|
299
310
|
return False
|
|
300
311
|
|
|
301
312
|
for nn in range(count1):
|
|
302
|
-
if
|
|
313
|
+
if (
|
|
314
|
+
self._items[(front1 + nn) % capacity1]
|
|
315
|
+
is other._items[(front2 + nn) % capacity2]
|
|
316
|
+
):
|
|
303
317
|
continue
|
|
304
|
-
if
|
|
318
|
+
if (
|
|
319
|
+
self._items[(front1 + nn) % capacity1]
|
|
320
|
+
!= other._items[(front2 + nn) % capacity2]
|
|
321
|
+
):
|
|
305
322
|
return False
|
|
306
323
|
return True
|
|
307
324
|
|
|
@@ -314,14 +331,14 @@ class CA[I]():
|
|
|
314
331
|
if self._cnt == self._cap:
|
|
315
332
|
self._double_storage_capacity()
|
|
316
333
|
(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
334
|
+
self._front,
|
|
335
|
+
self._items[self._front],
|
|
336
|
+
self._cnt,
|
|
320
337
|
) = (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
338
|
+
(self._front - 1) % self._cap,
|
|
339
|
+
item,
|
|
340
|
+
self._cnt + 1,
|
|
341
|
+
)
|
|
325
342
|
|
|
326
343
|
def pushr(self, *items: I) -> None:
|
|
327
344
|
"""Push ``items`` on from right.
|
|
@@ -332,14 +349,14 @@ class CA[I]():
|
|
|
332
349
|
if self._cnt == self._cap:
|
|
333
350
|
self._double_storage_capacity()
|
|
334
351
|
(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
352
|
+
self._rear,
|
|
353
|
+
self._items[self._rear],
|
|
354
|
+
self._cnt,
|
|
338
355
|
) = (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
356
|
+
(self._rear + 1) % self._cap,
|
|
357
|
+
item,
|
|
358
|
+
self._cnt + 1,
|
|
359
|
+
)
|
|
343
360
|
|
|
344
361
|
def popl(self) -> I:
|
|
345
362
|
"""Pop single item off from left side.
|
|
@@ -349,30 +366,30 @@ class CA[I]():
|
|
|
349
366
|
"""
|
|
350
367
|
if self._cnt > 1:
|
|
351
368
|
(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
369
|
+
d,
|
|
370
|
+
self._items[self._front],
|
|
371
|
+
self._front,
|
|
372
|
+
self._cnt,
|
|
356
373
|
) = (
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
374
|
+
self._items[self._front],
|
|
375
|
+
nada,
|
|
376
|
+
(self._front + 1) % self._cap,
|
|
377
|
+
self._cnt - 1,
|
|
378
|
+
)
|
|
362
379
|
elif self._cnt == 1:
|
|
363
380
|
(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
381
|
+
d,
|
|
382
|
+
self._items[self._front],
|
|
383
|
+
self._cnt,
|
|
384
|
+
self._front,
|
|
385
|
+
self._rear,
|
|
369
386
|
) = (
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
387
|
+
self._items[self._front],
|
|
388
|
+
nada,
|
|
389
|
+
0,
|
|
390
|
+
0,
|
|
391
|
+
self._cap - 1,
|
|
392
|
+
)
|
|
376
393
|
else:
|
|
377
394
|
msg = 'Method popl called on an empty CA'
|
|
378
395
|
raise ValueError(msg)
|
|
@@ -386,30 +403,30 @@ class CA[I]():
|
|
|
386
403
|
"""
|
|
387
404
|
if self._cnt > 1:
|
|
388
405
|
(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
406
|
+
d,
|
|
407
|
+
self._items[self._rear],
|
|
408
|
+
self._rear,
|
|
409
|
+
self._cnt,
|
|
393
410
|
) = (
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
411
|
+
self._items[self._rear],
|
|
412
|
+
nada,
|
|
413
|
+
(self._rear - 1) % self._cap,
|
|
414
|
+
self._cnt - 1,
|
|
415
|
+
)
|
|
399
416
|
elif self._cnt == 1:
|
|
400
417
|
(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
418
|
+
d,
|
|
419
|
+
self._items[self._front],
|
|
420
|
+
self._cnt,
|
|
421
|
+
self._front,
|
|
422
|
+
self._rear,
|
|
406
423
|
) = (
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
424
|
+
self._items[self._front],
|
|
425
|
+
nada,
|
|
426
|
+
0,
|
|
427
|
+
0,
|
|
428
|
+
self._cap - 1,
|
|
429
|
+
)
|
|
413
430
|
else:
|
|
414
431
|
msg = 'Method popr called on an empty CA'
|
|
415
432
|
raise ValueError(msg)
|
|
@@ -493,7 +510,7 @@ class CA[I]():
|
|
|
493
510
|
for _ in range(n, 0, -1):
|
|
494
511
|
self.pushl(self.popr())
|
|
495
512
|
|
|
496
|
-
def map[U](self, f: Callable[[I], U]) ->
|
|
513
|
+
def map[U](self, f: Callable[[I], U]) -> 'CA[U]':
|
|
497
514
|
"""Apply function ``f`` over the circular array's contents.
|
|
498
515
|
|
|
499
516
|
:param f: Callable from type ``I`` to type ``U``.
|
|
@@ -501,52 +518,62 @@ class CA[I]():
|
|
|
501
518
|
"""
|
|
502
519
|
return CA(map(f, self))
|
|
503
520
|
|
|
504
|
-
|
|
521
|
+
@overload
|
|
522
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
523
|
+
@overload
|
|
524
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
525
|
+
|
|
526
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L | NoValue = NoValue()) -> L:
|
|
505
527
|
"""Fold left with a function and optional starting item.
|
|
506
528
|
|
|
507
529
|
:param f: Folding function, first argument to ``f`` is for the accumulator.
|
|
508
|
-
:param start: Optional starting item.
|
|
530
|
+
:param start: "Optional" starting item.
|
|
509
531
|
:returns: Reduced value produced by the left fold.
|
|
510
532
|
:raises ValueError: When circular array empty and no starting item given.
|
|
511
533
|
"""
|
|
512
534
|
if self._cnt == 0:
|
|
513
|
-
if start is
|
|
535
|
+
if start is nada:
|
|
514
536
|
msg = 'Method foldl called on an empty CA without a start item.'
|
|
515
537
|
raise ValueError(msg)
|
|
516
|
-
return start
|
|
538
|
+
return cast(L, start)
|
|
517
539
|
|
|
518
|
-
if start is
|
|
540
|
+
if start is nada:
|
|
519
541
|
acc = cast(L, self[0]) # in this case D = L
|
|
520
542
|
for idx in range(1, self._cnt):
|
|
521
543
|
acc = f(acc, self[idx])
|
|
522
544
|
return acc
|
|
523
545
|
|
|
524
|
-
acc = start
|
|
546
|
+
acc = cast(L, start)
|
|
525
547
|
for d in self:
|
|
526
548
|
acc = f(acc, d)
|
|
527
549
|
return acc
|
|
528
550
|
|
|
529
|
-
|
|
551
|
+
@overload
|
|
552
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
553
|
+
@overload
|
|
554
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
555
|
+
|
|
556
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R | NoValue = nada) -> R:
|
|
530
557
|
"""Fold right with a function and an optional starting item.
|
|
531
558
|
|
|
532
559
|
:param f: Folding function, second argument to ``f`` is for the accumulator.
|
|
533
|
-
:param start: Optional starting item.
|
|
560
|
+
:param start: "Optional" starting item.
|
|
534
561
|
:returns: Reduced value produced by the right fold.
|
|
535
562
|
:raises ValueError: When circular array empty and no starting item given.
|
|
536
563
|
"""
|
|
537
564
|
if self._cnt == 0:
|
|
538
|
-
if start is
|
|
565
|
+
if start is nada:
|
|
539
566
|
msg = 'Method foldr called on empty CA without initial value.'
|
|
540
567
|
raise ValueError(msg)
|
|
541
|
-
return start
|
|
568
|
+
return cast(R, start)
|
|
542
569
|
|
|
543
|
-
if start is
|
|
570
|
+
if start is nada:
|
|
544
571
|
acc = cast(R, self[-1]) # in this case D = R
|
|
545
572
|
for idx in range(self._cnt - 2, -1, -1):
|
|
546
573
|
acc = f(self[idx], acc)
|
|
547
574
|
return acc
|
|
548
575
|
|
|
549
|
-
acc = start
|
|
576
|
+
acc = cast(R, start)
|
|
550
577
|
for d in reversed(self):
|
|
551
578
|
acc = f(d, acc)
|
|
552
579
|
return acc
|
|
@@ -561,16 +588,16 @@ class CA[I]():
|
|
|
561
588
|
def empty(self) -> None:
|
|
562
589
|
"""Empty the circular array, keep current storage capacity."""
|
|
563
590
|
(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
591
|
+
self._items,
|
|
592
|
+
self._front,
|
|
593
|
+
self._rear,
|
|
594
|
+
self._cnt,
|
|
568
595
|
) = (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
596
|
+
[nada] * self._cap,
|
|
597
|
+
0,
|
|
598
|
+
self._cap - 1,
|
|
599
|
+
0,
|
|
600
|
+
)
|
|
574
601
|
|
|
575
602
|
def fraction_filled(self) -> float:
|
|
576
603
|
"""Find fraction of the storage capacity which is filled.
|
|
@@ -589,12 +616,12 @@ class CA[I]():
|
|
|
589
616
|
self._compact_storage_capacity()
|
|
590
617
|
if (min_cap := minimum_capacity) > self._cap:
|
|
591
618
|
(
|
|
592
|
-
|
|
593
|
-
|
|
619
|
+
self._cap,
|
|
620
|
+
self._items,
|
|
594
621
|
) = (
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
622
|
+
min_cap,
|
|
623
|
+
self._items + [nada] * (min_cap - self._cap),
|
|
624
|
+
)
|
|
598
625
|
if self._cnt == 0:
|
|
599
626
|
self._front, self._rear = 0, self._cap - 1
|
|
600
627
|
|
|
@@ -4,7 +4,10 @@ from typing import overload
|
|
|
4
4
|
__all__ = ['CA', 'ca']
|
|
5
5
|
|
|
6
6
|
class CA[I]:
|
|
7
|
-
|
|
7
|
+
@overload
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
@overload
|
|
10
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
8
11
|
def __iter__(self) -> Iterator[I]: ...
|
|
9
12
|
def __reversed__(self) -> Iterator[I]: ...
|
|
10
13
|
def __bool__(self) -> bool: ...
|
|
@@ -33,8 +36,14 @@ class CA[I]:
|
|
|
33
36
|
def rotl(self, n: int = 1) -> None: ...
|
|
34
37
|
def rotr(self, n: int = 1) -> None: ...
|
|
35
38
|
def map[U](self, f: Callable[[I], U]) -> CA[U]: ...
|
|
36
|
-
|
|
37
|
-
def
|
|
39
|
+
@overload
|
|
40
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
41
|
+
@overload
|
|
42
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
43
|
+
@overload
|
|
44
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
45
|
+
@overload
|
|
46
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
38
47
|
def capacity(self) -> int: ...
|
|
39
48
|
def empty(self) -> None: ...
|
|
40
49
|
def fraction_filled(self) -> float: ...
|
|
@@ -18,44 +18,53 @@ Fixed Storage Capacity
|
|
|
18
18
|
|
|
19
19
|
**Circular array with fixed storage capacity.**
|
|
20
20
|
|
|
21
|
-
- O(1) pops and pushes either end
|
|
21
|
+
- O(1) pops and pushes either end
|
|
22
22
|
- O(1) indexing, does not support slicing
|
|
23
23
|
- fixed total storage capacity
|
|
24
|
-
- iterable,
|
|
24
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
25
25
|
- comparisons compare identity before equality, like builtins
|
|
26
26
|
- in boolean context, falsy when either empty or full, otherwise truthy
|
|
27
|
-
-
|
|
27
|
+
- function ``caf`` produces fixed capacity circular array from arguments
|
|
28
28
|
|
|
29
29
|
"""
|
|
30
|
+
|
|
30
31
|
from collections.abc import Callable, Iterable, Iterator
|
|
31
|
-
from typing import cast, Final
|
|
32
|
+
from typing import cast, Final, overload
|
|
33
|
+
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
32
34
|
|
|
33
35
|
__all__ = ['CAF', 'caf']
|
|
34
36
|
|
|
37
|
+
nada: Final[NoValue] = NoValue()
|
|
35
38
|
|
|
36
|
-
class CAF[I]():
|
|
37
39
|
|
|
40
|
+
class CAF[I]:
|
|
38
41
|
__slots__ = '_items', '_cnt', '_cap', '_front', '_rear'
|
|
39
42
|
|
|
43
|
+
@overload
|
|
44
|
+
def __init__(self) -> None: ...
|
|
45
|
+
@overload
|
|
46
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
47
|
+
@overload
|
|
48
|
+
def __init__(self, items: Iterable[I], capacity: int) -> None: ...
|
|
49
|
+
|
|
40
50
|
def __init__(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
capacity: int = 2
|
|
44
|
-
) -> None:
|
|
51
|
+
self, items: Iterable[I | NoValue] | NoValue = nada, capacity: int = 2
|
|
52
|
+
) -> None:
|
|
45
53
|
"""
|
|
46
|
-
:param items: Optional iterable to initial populate circular array.
|
|
47
|
-
:param capacity:
|
|
54
|
+
:param items: "Optional" iterable to initial populate circular array.
|
|
55
|
+
:param capacity: Minimum fixed storage capacity of circular array.
|
|
48
56
|
:raises TypeError: When ``items`` not Iterable,
|
|
49
57
|
"""
|
|
50
58
|
capacity = max(2, capacity)
|
|
51
|
-
if items is
|
|
52
|
-
self._items: list[I |
|
|
59
|
+
if items is nada:
|
|
60
|
+
self._items: list[I | NoValue] = [nada] * capacity
|
|
53
61
|
count = 0
|
|
54
62
|
else:
|
|
55
|
-
|
|
63
|
+
values: list[I | NoValue] = list(cast(Iterable[I | NoValue], items))
|
|
64
|
+
dlist: list[I | NoValue] = list(values)
|
|
56
65
|
count = len(dlist)
|
|
57
66
|
capacity = max(count, capacity)
|
|
58
|
-
self._items = dlist + [
|
|
67
|
+
self._items = dlist + [nada] * (capacity - count)
|
|
59
68
|
self._cap: Final[int] = capacity
|
|
60
69
|
self._cnt = count
|
|
61
70
|
if count == 0:
|
|
@@ -68,16 +77,16 @@ class CAF[I]():
|
|
|
68
77
|
def __iter__(self) -> Iterator[I]:
|
|
69
78
|
if self._cnt > 0:
|
|
70
79
|
(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
capacity,
|
|
81
|
+
rear,
|
|
82
|
+
position,
|
|
83
|
+
current_state,
|
|
75
84
|
) = (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
self._cap,
|
|
86
|
+
self._rear,
|
|
87
|
+
self._front,
|
|
88
|
+
self._items.copy(),
|
|
89
|
+
)
|
|
81
90
|
|
|
82
91
|
while position != rear:
|
|
83
92
|
yield cast(I, current_state[position])
|
|
@@ -87,16 +96,16 @@ class CAF[I]():
|
|
|
87
96
|
def __reversed__(self) -> Iterator[I]:
|
|
88
97
|
if self._cnt > 0:
|
|
89
98
|
(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
capacity,
|
|
100
|
+
front,
|
|
101
|
+
position,
|
|
102
|
+
current_state,
|
|
94
103
|
) = (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
self._cap,
|
|
105
|
+
self._front,
|
|
106
|
+
self._rear,
|
|
107
|
+
self._items.copy(),
|
|
108
|
+
)
|
|
100
109
|
|
|
101
110
|
while position != front:
|
|
102
111
|
yield cast(I, current_state[position])
|
|
@@ -152,16 +161,16 @@ class CAF[I]():
|
|
|
152
161
|
del item_list[idx]
|
|
153
162
|
_ca = CAF(item_list, self._cap)
|
|
154
163
|
(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
self._items,
|
|
165
|
+
self._cnt,
|
|
166
|
+
self._front,
|
|
167
|
+
self._rear,
|
|
159
168
|
) = (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
_ca._items,
|
|
170
|
+
_ca._cnt,
|
|
171
|
+
_ca._front,
|
|
172
|
+
_ca._rear,
|
|
173
|
+
)
|
|
165
174
|
del _ca
|
|
166
175
|
|
|
167
176
|
def __eq__(self, other: object) -> bool:
|
|
@@ -171,28 +180,34 @@ class CAF[I]():
|
|
|
171
180
|
return False
|
|
172
181
|
|
|
173
182
|
(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
front1,
|
|
184
|
+
count1,
|
|
185
|
+
capacity1,
|
|
186
|
+
front2,
|
|
187
|
+
count2,
|
|
188
|
+
capacity2,
|
|
180
189
|
) = (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
190
|
+
self._front,
|
|
191
|
+
self._cnt,
|
|
192
|
+
self._cap,
|
|
193
|
+
other._front,
|
|
194
|
+
other._cnt,
|
|
195
|
+
other._cap,
|
|
196
|
+
)
|
|
188
197
|
|
|
189
198
|
if count1 != count2:
|
|
190
199
|
return False
|
|
191
200
|
|
|
192
201
|
for nn in range(count1):
|
|
193
|
-
if
|
|
202
|
+
if (
|
|
203
|
+
self._items[(front1 + nn) % capacity1]
|
|
204
|
+
is other._items[(front2 + nn) % capacity2]
|
|
205
|
+
):
|
|
194
206
|
continue
|
|
195
|
-
if
|
|
207
|
+
if (
|
|
208
|
+
self._items[(front1 + nn) % capacity1]
|
|
209
|
+
!= other._items[(front2 + nn) % capacity2]
|
|
210
|
+
):
|
|
196
211
|
return False
|
|
197
212
|
return True
|
|
198
213
|
|
|
@@ -207,14 +222,14 @@ class CAF[I]():
|
|
|
207
222
|
raise ValueError(msg)
|
|
208
223
|
|
|
209
224
|
(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
225
|
+
self._front,
|
|
226
|
+
self._items[self._front],
|
|
227
|
+
self._cnt,
|
|
213
228
|
) = (
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
229
|
+
(self._front - 1) % self._cap,
|
|
230
|
+
item,
|
|
231
|
+
self._cnt + 1,
|
|
232
|
+
)
|
|
218
233
|
|
|
219
234
|
def pushr(self, item: I) -> None:
|
|
220
235
|
"""Push ``item`` on from Right.
|
|
@@ -227,14 +242,14 @@ class CAF[I]():
|
|
|
227
242
|
raise ValueError(msg)
|
|
228
243
|
|
|
229
244
|
(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
245
|
+
self._rear,
|
|
246
|
+
self._items[self._rear],
|
|
247
|
+
self._cnt,
|
|
233
248
|
) = (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
249
|
+
(self._rear + 1) % self._cap,
|
|
250
|
+
item,
|
|
251
|
+
self._cnt + 1,
|
|
252
|
+
)
|
|
238
253
|
|
|
239
254
|
def popl(self) -> I:
|
|
240
255
|
"""Pop single item off from left side.
|
|
@@ -244,30 +259,30 @@ class CAF[I]():
|
|
|
244
259
|
"""
|
|
245
260
|
if self._cnt > 1:
|
|
246
261
|
(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
d,
|
|
263
|
+
self._items[self._front],
|
|
264
|
+
self._front,
|
|
265
|
+
self._cnt,
|
|
251
266
|
) = (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
267
|
+
self._items[self._front],
|
|
268
|
+
nada,
|
|
269
|
+
(self._front + 1) % self._cap,
|
|
270
|
+
self._cnt - 1,
|
|
271
|
+
)
|
|
257
272
|
elif self._cnt == 1:
|
|
258
273
|
(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
274
|
+
d,
|
|
275
|
+
self._items[self._front],
|
|
276
|
+
self._cnt,
|
|
277
|
+
self._front,
|
|
278
|
+
self._rear,
|
|
264
279
|
) = (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
280
|
+
self._items[self._front],
|
|
281
|
+
nada,
|
|
282
|
+
0,
|
|
283
|
+
0,
|
|
284
|
+
self._cap - 1,
|
|
285
|
+
)
|
|
271
286
|
else:
|
|
272
287
|
msg = 'Method popl called on an empty CAF'
|
|
273
288
|
raise ValueError(msg)
|
|
@@ -281,30 +296,30 @@ class CAF[I]():
|
|
|
281
296
|
"""
|
|
282
297
|
if self._cnt > 1:
|
|
283
298
|
(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
299
|
+
d,
|
|
300
|
+
self._items[self._rear],
|
|
301
|
+
self._rear,
|
|
302
|
+
self._cnt,
|
|
288
303
|
) = (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
304
|
+
self._items[self._rear],
|
|
305
|
+
nada,
|
|
306
|
+
(self._rear - 1) % self._cap,
|
|
307
|
+
self._cnt - 1,
|
|
308
|
+
)
|
|
294
309
|
elif self._cnt == 1:
|
|
295
310
|
(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
311
|
+
d,
|
|
312
|
+
self._items[self._front],
|
|
313
|
+
self._cnt,
|
|
314
|
+
self._front,
|
|
315
|
+
self._rear,
|
|
301
316
|
) = (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
317
|
+
self._items[self._front],
|
|
318
|
+
nada,
|
|
319
|
+
0,
|
|
320
|
+
0,
|
|
321
|
+
self._cap - 1,
|
|
322
|
+
)
|
|
308
323
|
else:
|
|
309
324
|
msg = 'Method popr called on an empty CAF'
|
|
310
325
|
raise ValueError(msg)
|
|
@@ -388,7 +403,7 @@ class CAF[I]():
|
|
|
388
403
|
for _ in range(n, 0, -1):
|
|
389
404
|
self.pushl(self.popr())
|
|
390
405
|
|
|
391
|
-
def map[U](self, f: Callable[[I], U]) ->
|
|
406
|
+
def map[U](self, f: Callable[[I], U]) -> 'CAF[U]':
|
|
392
407
|
"""Apply function ``f`` over the circular array's contents,
|
|
393
408
|
|
|
394
409
|
:param f: Callable from type ``I`` to type ``U``.
|
|
@@ -396,7 +411,12 @@ class CAF[I]():
|
|
|
396
411
|
"""
|
|
397
412
|
return CAF(map(f, self), self._cap)
|
|
398
413
|
|
|
399
|
-
|
|
414
|
+
@overload
|
|
415
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
416
|
+
@overload
|
|
417
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
418
|
+
|
|
419
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L | NoValue = nada) -> L:
|
|
400
420
|
"""Fold left with a function and optional stating item.
|
|
401
421
|
|
|
402
422
|
:param f: Folding function, first argument to ``f`` is for the accumulator.
|
|
@@ -405,23 +425,28 @@ class CAF[I]():
|
|
|
405
425
|
:raises ValueError: When circular array empty and no starting item given.
|
|
406
426
|
"""
|
|
407
427
|
if self._cnt == 0:
|
|
408
|
-
if start is
|
|
428
|
+
if start is nada:
|
|
409
429
|
msg = 'Method foldl called on an empty CAF without a start item.'
|
|
410
430
|
raise ValueError(msg)
|
|
411
|
-
return start
|
|
431
|
+
return cast(L, start)
|
|
412
432
|
|
|
413
|
-
if start is
|
|
433
|
+
if start is nada:
|
|
414
434
|
acc = cast(L, self[0]) # in this case D = L
|
|
415
435
|
for idx in range(1, self._cnt):
|
|
416
436
|
acc = f(acc, self[idx])
|
|
417
437
|
return acc
|
|
418
438
|
|
|
419
|
-
acc = start
|
|
439
|
+
acc = cast(L, start)
|
|
420
440
|
for d in self:
|
|
421
441
|
acc = f(acc, d)
|
|
422
442
|
return acc
|
|
423
443
|
|
|
424
|
-
|
|
444
|
+
@overload
|
|
445
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
446
|
+
@overload
|
|
447
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
448
|
+
|
|
449
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R | NoValue = nada) -> R:
|
|
425
450
|
"""Fold right with a function and an optional starting item.
|
|
426
451
|
|
|
427
452
|
:param f: Folding function, second argument to ``f`` is for the accumulator.
|
|
@@ -430,18 +455,18 @@ class CAF[I]():
|
|
|
430
455
|
:raises ValueError: When circular array empty and no starting item given.
|
|
431
456
|
"""
|
|
432
457
|
if self._cnt == 0:
|
|
433
|
-
if start is
|
|
458
|
+
if start is nada:
|
|
434
459
|
msg = 'Method foldr called on empty CAF without initial value.'
|
|
435
460
|
raise ValueError(msg)
|
|
436
|
-
return start
|
|
461
|
+
return cast(R, start)
|
|
437
462
|
|
|
438
|
-
if start is
|
|
463
|
+
if start is nada:
|
|
439
464
|
acc = cast(R, self[-1]) # in this case D = R
|
|
440
465
|
for idx in range(self._cnt - 2, -1, -1):
|
|
441
466
|
acc = f(self[idx], acc)
|
|
442
467
|
return acc
|
|
443
468
|
|
|
444
|
-
acc = start
|
|
469
|
+
acc = cast(R, start)
|
|
445
470
|
for d in reversed(self):
|
|
446
471
|
acc = f(d, acc)
|
|
447
472
|
return acc
|
|
@@ -456,16 +481,16 @@ class CAF[I]():
|
|
|
456
481
|
def empty(self) -> None:
|
|
457
482
|
"""Empty the circular array."""
|
|
458
483
|
(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
484
|
+
self._items,
|
|
485
|
+
self._front,
|
|
486
|
+
self._rear,
|
|
487
|
+
self._cnt,
|
|
463
488
|
) = (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
489
|
+
[nada] * self._cap,
|
|
490
|
+
0,
|
|
491
|
+
self._cap - 1,
|
|
492
|
+
0,
|
|
493
|
+
)
|
|
469
494
|
|
|
470
495
|
def fraction_filled(self) -> float:
|
|
471
496
|
"""Find fraction of the storage capacity which is filled.
|
|
@@ -482,4 +507,4 @@ def caf[T](*items: T, capacity: int = 2) -> CAF[T]:
|
|
|
482
507
|
:param capacity: The minimum storage capacity to set.
|
|
483
508
|
:returns: New fixed storage capacity circular array.
|
|
484
509
|
"""
|
|
485
|
-
return CAF(items, capacity
|
|
510
|
+
return CAF(items, capacity=capacity)
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
from collections.abc import Callable, Iterable, Iterator
|
|
2
|
+
from typing import overload
|
|
2
3
|
|
|
3
4
|
__all__ = ['CAF', 'caf']
|
|
4
5
|
|
|
5
6
|
class CAF[I]:
|
|
6
|
-
|
|
7
|
+
@overload
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
@overload
|
|
10
|
+
def __init__(self, items: Iterable[I]) -> None: ...
|
|
11
|
+
@overload
|
|
12
|
+
def __init__(self, items: Iterable[I], capacity: int) -> None: ...
|
|
7
13
|
def __iter__(self) -> Iterator[I]: ...
|
|
8
14
|
def __reversed__(self) -> Iterator[I]: ...
|
|
9
15
|
def __bool__(self) -> bool: ...
|
|
@@ -23,8 +29,14 @@ class CAF[I]:
|
|
|
23
29
|
def rotl(self, n: int = 1) -> None: ...
|
|
24
30
|
def rotr(self, n: int = 1) -> None: ...
|
|
25
31
|
def map[U](self, f: Callable[[I], U]) -> CAF[U]: ...
|
|
26
|
-
|
|
27
|
-
def
|
|
32
|
+
@overload
|
|
33
|
+
def foldl[L](self, f: Callable[[I, I], I]) -> I: ...
|
|
34
|
+
@overload
|
|
35
|
+
def foldl[L](self, f: Callable[[L, I], L], start: L) -> L: ...
|
|
36
|
+
@overload
|
|
37
|
+
def foldr[R](self, f: Callable[[I, I], I]) -> I: ...
|
|
38
|
+
@overload
|
|
39
|
+
def foldr[R](self, f: Callable[[I, R], R], start: R) -> R: ...
|
|
28
40
|
def capacity(self) -> int: ...
|
|
29
41
|
def empty(self) -> None: ...
|
|
30
42
|
def fraction_filled(self) -> float: ...
|
{pythonic_fp_circulararray-5.3.3.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-circulararray
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.4.0
|
|
4
4
|
Summary: Circular Array
|
|
5
5
|
Keywords: auto resizing,circular array,circulararray,dequeue,indexable,pop,push
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
@@ -14,6 +14,7 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Classifier: Typing :: Typed
|
|
16
16
|
License-File: LICENSE
|
|
17
|
+
Requires-Dist: pythonic-fp-gadgets>=3.1.0
|
|
17
18
|
Requires-Dist: pytest>=8.4.1 ; extra == "test"
|
|
18
19
|
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-circulararray/blob/main/CHANGELOG.rst
|
|
19
20
|
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/circulararray/development/build/html/index.html
|
|
@@ -30,17 +31,31 @@ PyPI project
|
|
|
30
31
|
|
|
31
32
|
Python module implementing stateful circular array data structures.
|
|
32
33
|
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
- O(1)
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
- variable storage capacity circular array
|
|
35
|
+
|
|
36
|
+
- O(1) pops either end
|
|
37
|
+
- O(1) amortized pushes either end
|
|
38
|
+
- O(1) indexing, fully supports slicing
|
|
39
|
+
- auto-resizing more storage capacity when necessary, manually compatible
|
|
40
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
41
|
+
- comparisons compare identity before equality, like builtins
|
|
42
|
+
- in boolean context, falsy when empty, otherwise truthy
|
|
43
|
+
- function ``ca`` produces auto-resizing circular array from arguments
|
|
44
|
+
|
|
45
|
+
- fixed storage capacity circular array
|
|
46
|
+
|
|
47
|
+
- O(1) pops and pushes either end
|
|
48
|
+
- O(1) indexing, does not support slicing
|
|
49
|
+
- fixed total storage capacity
|
|
50
|
+
- iterable, safely mutates while iterators iterating over previous state
|
|
51
|
+
- comparisons compare identity before equality, like builtins
|
|
52
|
+
- in boolean context, falsy when either empty or full, otherwise truthy
|
|
53
|
+
- function ``caf`` produces fixed capacity circular array from arguments
|
|
54
|
+
|
|
55
|
+
Part of the
|
|
56
|
+
`pythonic-fp
|
|
57
|
+
<https://grscheller.github.io/pythonic-fp/homepage/build/html/index.html>`_
|
|
58
|
+
PyPI projects.
|
|
44
59
|
|
|
45
60
|
Documentation
|
|
46
61
|
-------------
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
pythonic_fp/circulararray/__init__.py,sha256=uR0KASmw1Zraz9l3VPbqPm9WUKzWk-0_tUGT0opabzQ,1515
|
|
2
|
+
pythonic_fp/circulararray/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
pythonic_fp/circulararray/auto.py,sha256=mM5kAZnSo4etgA0uSp05VUMGpIOeKXIoCCQ1C3pIETo,19457
|
|
4
|
+
pythonic_fp/circulararray/auto.pyi,sha256=DegIbRFv66Ws4N1J1dExQ6cQJOTZw-XXUEJHi1OgIBk,1861
|
|
5
|
+
pythonic_fp/circulararray/fixed.py,sha256=VhCWBcE0C8toYqGyd9aKJ1bSJu8sHA46AQGJ7mGxYBE,15700
|
|
6
|
+
pythonic_fp/circulararray/fixed.pyi,sha256=Uk0QnXn3_q_6urXeRFEMxsL0gS-3Xa4UsyDRVXk8YoY,1648
|
|
7
|
+
pythonic_fp/circulararray/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
pythonic_fp_circulararray-5.4.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
9
|
+
pythonic_fp_circulararray-5.4.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
10
|
+
pythonic_fp_circulararray-5.4.0.dist-info/METADATA,sha256=x6ZQX_ItPF3ndJZFS15JOOqKPK01yM6YEf0Y3e9PsK8,2761
|
|
11
|
+
pythonic_fp_circulararray-5.4.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
pythonic_fp/circulararray/__init__.py,sha256=uR0KASmw1Zraz9l3VPbqPm9WUKzWk-0_tUGT0opabzQ,1515
|
|
2
|
-
pythonic_fp/circulararray/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
pythonic_fp/circulararray/auto.py,sha256=_rZhOsC3PGs97j15qM4vXpkpRDTfVkxEGwYyBi9uAQU,19334
|
|
4
|
-
pythonic_fp/circulararray/auto.pyi,sha256=yfQ2kzIiXFb2Bpg3cMwHwv2oSlyOUMTgmdPZM_-oU_8,1669
|
|
5
|
-
pythonic_fp/circulararray/fixed.py,sha256=nzwPnaVOh-KKv503_c--f_m0SkOaUI6mSe1Bo5WACCA,15316
|
|
6
|
-
pythonic_fp/circulararray/fixed.pyi,sha256=y_7eMvH18B1lpLPp2P-VkN-xcQVKJn6cOisp9LSBBRk,1362
|
|
7
|
-
pythonic_fp/circulararray/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
pythonic_fp_circulararray-5.3.3.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
9
|
-
pythonic_fp_circulararray-5.3.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
10
|
-
pythonic_fp_circulararray-5.3.3.dist-info/METADATA,sha256=rdgGmosD6wF1Cfye7QBuZJXGnjs3uDgPzmYYvVpUx-M,2180
|
|
11
|
-
pythonic_fp_circulararray-5.3.3.dist-info/RECORD,,
|
{pythonic_fp_circulararray-5.3.3.dist-info → pythonic_fp_circulararray-5.4.0.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|