dtools.circular-array 3.10.1__py3-none-any.whl → 3.12.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.
@@ -12,18 +12,25 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """### Developer Tools - circular array data structure
15
+ """### Developer Tools - Circular Array Data Structure
16
16
 
17
17
  Package for an indexable, sliceable, auto-resizing circular array
18
18
  data structure with amortized O(1) pushes and pops either end.
19
19
 
20
- #### Modules
20
+ #### Circular Array Data Structure
21
21
 
22
- * module dtools.circular_array.ca: circular array data structure
22
+ ##### *module* dtools.circular_array.ca
23
+
24
+ Circular array data structure.
25
+
26
+ - *class* dtools.circular_array.ca.CA
27
+ - initializer takes 1 or 0 iterables
28
+ - *function* dtools.circular_array.ca.ca
29
+ - factory function taking a variable number of arguments
23
30
 
24
31
  """
25
32
 
26
- __version__ = '3.10.1'
33
+ __version__ = '3.12.0'
27
34
  __author__ = 'Geoffrey R. Scheller'
28
35
  __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
29
36
  __license__ = 'Apache License 2.0'
@@ -15,18 +15,19 @@
15
15
  """### Module for an indexable circular array data structure."""
16
16
 
17
17
  from __future__ import annotations
18
- from collections.abc import Callable, Iterable, Iterator, Sequence
18
+ from collections.abc import Callable, Iterable, Iterator
19
19
  from typing import cast, Never, overload, TypeVar
20
20
 
21
- __all__ = ['ca', 'CA']
21
+ __all__ = ['CA', 'ca']
22
22
 
23
- D = TypeVar('D') # Not needed for mypy, hint for pdoc.
24
- L = TypeVar('L')
25
- R = TypeVar('R')
26
- U = TypeVar('U')
23
+ D = TypeVar('D') # Needed only for pdoc documentation generation. Otherwise,
24
+ L = TypeVar('L') # ignored by both MyPy and Python. Makes linters unhappy
25
+ R = TypeVar('R') # when these are used on function and method signatures due
26
+ U = TypeVar('U') # to "redefined-outer-name" warnings. Function and method
27
+ T = TypeVar('T') # signatures do not support variance and bounds constraints.
27
28
 
28
29
 
29
- class ca[D](Sequence[D]):
30
+ class CA[D]():
30
31
  """Indexable circular array data structure
31
32
 
32
33
  - generic, stateful data structure
@@ -52,7 +53,7 @@ class ca[D](Sequence[D]):
52
53
  [None] + cast(list[D | None], list(*dss)) + [None]
53
54
  )
54
55
  else:
55
- msg = f'ca expected at most 1 argument, got {len(dss)}'
56
+ msg = f'CA expected at most 1 argument, got {len(dss)}'
56
57
  raise TypeError(msg)
57
58
  self._cap = cap = len(self._data)
58
59
  self._cnt = cap - 2
@@ -76,7 +77,7 @@ class ca[D](Sequence[D]):
76
77
  self._front, self._cap = self._front + self._cap, 2 * self._cap
77
78
 
78
79
  def _compact_storage_capacity(self) -> None:
79
- """Compact the ca."""
80
+ """Compact the CA."""
80
81
  match self._cnt:
81
82
  case 0:
82
83
  self._cap, self._front, self._rear, self._data = 2, 0, 1, [None, None]
@@ -135,7 +136,7 @@ class ca[D](Sequence[D]):
135
136
  yield cast(D, current_state[position])
136
137
 
137
138
  def __repr__(self) -> str:
138
- return 'CA(' + ', '.join(map(repr, self)) + ')'
139
+ return 'ca(' + ', '.join(map(repr, self)) + ')'
139
140
 
140
141
  def __str__(self) -> str:
141
142
  return '(|' + ', '.join(map(str, self)) + '|)'
@@ -149,11 +150,11 @@ class ca[D](Sequence[D]):
149
150
  @overload
150
151
  def __getitem__(self, idx: int, /) -> D: ...
151
152
  @overload
152
- def __getitem__(self, idx: slice, /) -> ca[D]: ...
153
+ def __getitem__(self, idx: slice, /) -> CA[D]: ...
153
154
 
154
- def __getitem__(self, idx: int | slice, /) -> D | ca[D]:
155
+ def __getitem__(self, idx: int | slice, /) -> D | CA[D]:
155
156
  if isinstance(idx, slice):
156
- return ca(list(self)[idx])
157
+ return CA(list(self)[idx])
157
158
 
158
159
  cnt = self._cnt
159
160
  if 0 <= idx < cnt:
@@ -163,12 +164,12 @@ class ca[D](Sequence[D]):
163
164
  return cast(D, self._data[(self._front + cnt + idx) % self._cap])
164
165
 
165
166
  if cnt == 0:
166
- msg0 = 'Trying to get a value from an empty ca.'
167
+ msg0 = 'Trying to get a value from an empty CA.'
167
168
  raise IndexError(msg0)
168
169
 
169
170
  msg1 = 'Out of bounds: '
170
171
  msg2 = f'index = {idx} not between {-cnt} and {cnt - 1} '
171
- msg3 = 'while getting value from a ca.'
172
+ msg3 = 'while getting value from a CA.'
172
173
  raise IndexError(msg1 + msg2 + msg3)
173
174
 
174
175
  @overload
@@ -181,7 +182,7 @@ class ca[D](Sequence[D]):
181
182
  if isinstance(vals, Iterable):
182
183
  data = list(self)
183
184
  data[idx] = vals
184
- _ca = ca(data)
185
+ _ca = CA(data)
185
186
  self._data, self._cnt, self._cap, self._front, self._rear = (
186
187
  _ca._data,
187
188
  _ca._cnt,
@@ -201,12 +202,12 @@ class ca[D](Sequence[D]):
201
202
  self._data[(self._front + cnt + idx) % self._cap] = cast(D, vals)
202
203
  else:
203
204
  if cnt < 1:
204
- msg0 = 'Trying to set a value from an empty ca.'
205
+ msg0 = 'Trying to set a value from an empty CA.'
205
206
  raise IndexError(msg0)
206
207
 
207
208
  msg1 = 'Out of bounds: '
208
209
  msg2 = f'index = {idx} not between {-cnt} and {cnt - 1} '
209
- msg3 = 'while setting value from a ca.'
210
+ msg3 = 'while setting value from a CA.'
210
211
  raise IndexError(msg1 + msg2 + msg3)
211
212
 
212
213
  @overload
@@ -217,7 +218,7 @@ class ca[D](Sequence[D]):
217
218
  def __delitem__(self, idx: int | slice) -> None:
218
219
  data = list(self)
219
220
  del data[idx]
220
- _ca = ca(data)
221
+ _ca = CA(data)
221
222
  self._data, self._cnt, self._cap, self._front, self._rear = (
222
223
  _ca._data,
223
224
  _ca._cnt,
@@ -258,7 +259,7 @@ class ca[D](Sequence[D]):
258
259
  return True
259
260
 
260
261
  def pushl(self, *ds: D) -> None:
261
- """Push data from the left onto the ca."""
262
+ """Push data from the left onto the CA."""
262
263
  for d in ds:
263
264
  if self._cnt == self._cap:
264
265
  self._double_storage_capacity()
@@ -266,7 +267,7 @@ class ca[D](Sequence[D]):
266
267
  self._data[self._front], self._cnt = d, self._cnt + 1
267
268
 
268
269
  def pushr(self, *ds: D) -> None:
269
- """Push data from the right onto the ca."""
270
+ """Push data from the right onto the CA."""
270
271
  for d in ds:
271
272
  if self._cnt == self._cap:
272
273
  self._double_storage_capacity()
@@ -274,9 +275,9 @@ class ca[D](Sequence[D]):
274
275
  self._data[self._rear], self._cnt = d, self._cnt + 1
275
276
 
276
277
  def popl(self) -> D | Never:
277
- """Pop one value off the left side of the ca.
278
+ """Pop one value off the left side of the CA.
278
279
 
279
- Raises `ValueError` when called on an empty ca.
280
+ Raises `ValueError` when called on an empty CA.
280
281
 
281
282
  """
282
283
  if self._cnt > 1:
@@ -295,14 +296,14 @@ class ca[D](Sequence[D]):
295
296
  self._cap - 1,
296
297
  )
297
298
  else:
298
- msg = 'Method popl called on an empty ca'
299
+ msg = 'Method popl called on an empty CA'
299
300
  raise ValueError(msg)
300
301
  return cast(D, d)
301
302
 
302
303
  def popr(self) -> D | Never:
303
- """Pop one value off the right side of the ca.
304
+ """Pop one value off the right side of the CA.
304
305
 
305
- Raises `ValueError` when called on an empty ca.
306
+ Raises `ValueError` when called on an empty CA.
306
307
 
307
308
  """
308
309
  if self._cnt > 1:
@@ -321,7 +322,7 @@ class ca[D](Sequence[D]):
321
322
  self._cap - 1,
322
323
  )
323
324
  else:
324
- msg = 'Method popr called on an empty ca'
325
+ msg = 'Method popr called on an empty CA'
325
326
  raise ValueError(msg)
326
327
  return cast(D, d)
327
328
 
@@ -329,7 +330,7 @@ class ca[D](Sequence[D]):
329
330
  """Pop one value from left, provide a mandatory default value.
330
331
 
331
332
  - safe version of popl
332
- - returns a default value in the event the `ca` is empty
333
+ - returns a default value in the event the `CA` is empty
333
334
 
334
335
  """
335
336
  try:
@@ -341,7 +342,7 @@ class ca[D](Sequence[D]):
341
342
  """Pop one value from right, provide a mandatory default value.
342
343
 
343
344
  - safe version of popr
344
- - returns a default value in the event the `ca` is empty
345
+ - returns a default value in the event the `CA` is empty
345
346
 
346
347
  """
347
348
  try:
@@ -349,74 +350,72 @@ class ca[D](Sequence[D]):
349
350
  except ValueError:
350
351
  return default
351
352
 
352
- def poplt(self, max: int) -> tuple[D, ...]:
353
- """Pop multiple values from left side of ca.
353
+ def poplt(self, maximum: int, /) -> tuple[D, ...]:
354
+ """Pop multiple values from left side of `CA`.
354
355
 
355
356
  - returns the results in a tuple of type `tuple[~D, ...]`
356
- - returns an empty tuple if `ca` is empty
357
+ - returns an empty tuple if `CA` is empty
357
358
  - pop no more that `max` values
358
- - will pop less if `ca` becomes empty
359
+ - will pop less if `CA` becomes empty
359
360
 
360
361
  """
361
362
  ds: list[D] = []
362
363
 
363
- while max > 0:
364
+ while maximum > 0:
364
365
  try:
365
366
  ds.append(self.popl())
366
367
  except ValueError:
367
368
  break
368
369
  else:
369
- max -= 1
370
+ maximum -= 1
370
371
 
371
372
  return tuple(ds)
372
373
 
373
- def poprt(self, max: int) -> tuple[D, ...]:
374
- """Pop multiple values from right side of `ca`.
374
+ def poprt(self, maximum: int, /) -> tuple[D, ...]:
375
+ """Pop multiple values from right side of `CA`.
375
376
 
376
377
  - returns the results in a tuple of type `tuple[~D, ...]`
377
- - returns an empty tuple if `ca` is empty
378
+ - returns an empty tuple if `CA` is empty
378
379
  - pop no more that `max` values
379
- - will pop less if `ca` becomes empty
380
+ - will pop less if `CA` becomes empty
380
381
 
381
382
  """
382
383
  ds: list[D] = []
383
- while max > 0:
384
+ while maximum > 0:
384
385
  try:
385
386
  ds.append(self.popr())
386
387
  except ValueError:
387
388
  break
388
389
  else:
389
- max -= 1
390
+ maximum -= 1
390
391
 
391
392
  return tuple(ds)
392
393
 
393
- def rotl(self, n: int = 1) -> None:
394
- """Rotate ca arguments left n times."""
394
+ def rotl(self, n: int = 1, /) -> None:
395
+ """Rotate `CA` arguments left n times."""
395
396
  if self._cnt < 2:
396
397
  return
397
- while n > 0:
398
+ for _ in range(n, 0, -1):
398
399
  self.pushr(self.popl())
399
- n -= 1
400
400
 
401
- def rotr(self, n: int = 1) -> None:
402
- """Rotate ca arguments right n times."""
401
+ def rotr(self, n: int = 1, /) -> None:
402
+ """Rotate `CA` arguments right n times."""
403
403
  if self._cnt < 2:
404
404
  return
405
- while n > 0:
405
+ for _ in range(n, 0, -1):
406
406
  self.pushl(self.popr())
407
- n -= 1
408
407
 
409
- def map[U](self, f: Callable[[D], U], /) -> ca[U]:
410
- """Apply function f over contents, returns new `ca` instance.
408
+ def map[U](self, f: Callable[[D], U], /) -> CA[U]:
409
+ """Apply function f over contents, returns new `CA` instance.
411
410
 
412
- - parameter `f` function of type `f[~D, ~U] -> ca[~U]`
413
- - returns a new instance of type `ca[~U]`
411
+ - parameter `f` function of type `f[~D, ~U] -> CA[~U]`
412
+ - returns a new instance of type `CA[~U]`
414
413
 
415
414
  """
416
- return ca(map(f, self))
415
+ return CA(map(f, self))
417
416
 
418
417
  def foldl[L](self, f: Callable[[L, D], L], /, initial: L | None = None) -> L:
419
- """Left fold ca via function and optional initial value.
418
+ """Left fold `CA` via function and optional initial value.
420
419
 
421
420
  - parameter `f` function of type `f[~L, ~D] -> ~L`
422
421
  - the first argument to `f` is for the accumulated value.
@@ -429,7 +428,7 @@ class ca[D](Sequence[D]):
429
428
  """
430
429
  if self._cnt == 0:
431
430
  if initial is None:
432
- msg = 'Method foldL called on an empty ca without an initial value.'
431
+ msg = 'Method foldl called on an empty `CA` without an initial value.'
433
432
  raise ValueError(msg)
434
433
  return initial
435
434
 
@@ -445,7 +444,7 @@ class ca[D](Sequence[D]):
445
444
  return acc
446
445
 
447
446
  def foldr[R](self, f: Callable[[D, R], R], /, initial: R | None = None) -> R:
448
- """Right fold ca via function and optional initial value.
447
+ """Right fold `CA` via function and optional initial value.
449
448
 
450
449
  - parameter `f` function of type `f[~D, ~R] -> ~R`
451
450
  - the second argument to f is for the accumulated value
@@ -453,12 +452,12 @@ class ca[D](Sequence[D]):
453
452
  - returns the reduced value of type `~R`
454
453
  - note that `~R` and `~D` can be the same type
455
454
  - if an initial value is not given then by necessity `~R = ~D`
456
- - raises `ValueError` when called on an empty `ca` and `initial` not given
455
+ - raises `ValueError` when called on an empty `CA` and `initial` not given
457
456
 
458
457
  """
459
458
  if self._cnt == 0:
460
459
  if initial is None:
461
- msg = 'Method foldr called on an empty ca without an initial value.'
460
+ msg = 'Method foldr called on empty `CA` without initial value.'
462
461
  raise ValueError(msg)
463
462
  return initial
464
463
 
@@ -474,21 +473,21 @@ class ca[D](Sequence[D]):
474
473
  return acc
475
474
 
476
475
  def capacity(self) -> int:
477
- """Returns current capacity of the ca."""
476
+ """Returns current capacity of the `CA`."""
478
477
  return self._cap
479
478
 
480
479
  def empty(self) -> None:
481
- """Empty the ca, keep current capacity."""
480
+ """Empty the `CA`, keep current capacity."""
482
481
  self._data, self._front, self._rear = [None] * self._cap, 0, self._cap
483
482
 
484
483
  def fraction_filled(self) -> float:
485
- """Returns fractional capacity of the ca."""
484
+ """Returns fractional capacity of the `CA`."""
486
485
  return self._cnt / self._cap
487
486
 
488
487
  def resize(self, minimum_capacity: int = 2) -> None:
489
- """Compact `ca` and resize to `minimum_capacity` if necessary.
488
+ """Compact `CA` and resize to `minimum_capacity` if necessary.
490
489
 
491
- To just compact the `ca`, do not provide a minimum capacity.
490
+ * to just compact the `CA`, do not provide a minimum capacity
492
491
 
493
492
  """
494
493
  self._compact_storage_capacity()
@@ -498,11 +497,6 @@ class ca[D](Sequence[D]):
498
497
  self._front, self._rear = 0, self._cap - 1
499
498
 
500
499
 
501
- def CA[D](*ds: D) -> ca[D]:
502
- """Function to produce a `ca` array from a variable number of arguments.
503
-
504
- Upper case function name used to stand out in place of syntactic sugar
505
- used by builtins, like `[]` for list or `{}` for dict or set.
506
-
507
- """
508
- return ca(ds)
500
+ def ca[T](*ds: T) -> CA[T]:
501
+ """Function to produce a `CA` array from a variable number of arguments."""
502
+ return CA(ds)
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtools.circular-array
3
- Version: 3.10.1
4
- Summary: ### Developer Tools - circular array data structure
5
- Keywords: circular array,circle array,ca,double ended queue,dequeue,dqueue,pop,push,popl,popr,pushl,pushr,indexable,auto-resizing,auto resizing,resizing
3
+ Version: 3.12.0
4
+ Summary: ### Developer Tools - Circular Array Data Structure
5
+ Keywords: circular array,circle array,CA,dequeue,dqueue,FIFO,LIFO,pop,push,indexable,auto-resizing,auto resizing,resizing
6
6
  Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
7
7
  Requires-Python: >=3.12
8
8
  Description-Content-Type: text/markdown
@@ -61,38 +61,37 @@ syntactic sugar like `[]` or `{}`.
61
61
  #### Usage
62
62
 
63
63
  ```python
64
- from dtools.circular_array.ca import CA
64
+ from dtools.circular_array.ca import CA, ca
65
65
 
66
- ca = CA(1, 2, 3)
67
- assert ca.popl() == 1
68
- assert ca.popr() == 3
69
- ca.pushr(42, 0)
70
- ca.pushl(0, 1)
71
- assert repr(ca) == 'CA(1, 0, 2, 42, 0)'
72
- assert str(ca) == '(|1, 0, 2, 42, 0|)'
66
+ ca1 = ca(1, 2, 3)
67
+ assert ca1.popl() == 1
68
+ assert ca1.popr() == 3
69
+ ca1.pushr(42, 0)
70
+ ca1.pushl(0, 1)
71
+ assert repr(ca1) == 'ca(1, 0, 2, 42, 0)'
72
+ assert str(ca1) == '(|1, 0, 2, 42, 0|)'
73
73
 
74
- ca = ca(range(1,11))
75
- assert repr(ca) == 'CA(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)'
76
- assert str(ca) == '(|1, 2, 3, 4, 5, 6, 7, 8, 9, 10|)'
77
- assert len(ca) == 10
78
- tup3 = ca.poplt(3)
79
- tup4 = ca.poprt(4)
74
+ ca2 = CA(range(1,11))
75
+ assert repr(ca2) == 'ca(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)'
76
+ assert str(ca2) == '(|1, 2, 3, 4, 5, 6, 7, 8, 9, 10|)'
77
+ assert len(ca2) == 10
78
+ tup3 = ca2.poplt(3)
79
+ tup4 = ca2.poprt(4)
80
80
  assert tup3 == (1, 2, 3)
81
81
  assert tup4 == (10, 9, 8, 7)
82
-
83
- assert ca == CA(4, 5, 6)
82
+ assert ca2 == CA(4, 5, 6)
84
83
  four, *rest = ca.popft(1000)
85
84
  assert four == 4
86
85
  assert rest == [5, 6]
87
- assert len(ca) == 0
86
+ assert len(ca2) == 0
88
87
 
89
- ca = ca([1, 2, 3])
90
- assert ca.popld(42) == 1
91
- assert ca.poprd(42) == 3
92
- assert ca.popld(42) == 2
93
- assert ca.poprd(42) == 42
94
- assert ca.popld(42) == 42
95
- assert len(ca) == 0
88
+ ca3 = CA([1, 2, 3])
89
+ assert ca3.popld(42) == 1
90
+ assert ca3.poprd(42) == 3
91
+ assert ca3.popld(42) == 2
92
+ assert ca3.poprd(42) == 42
93
+ assert ca3.popld(42) == 42
94
+ assert len(ca2) == 0
96
95
  ```
97
96
 
98
97
  ______________________________________________________________________
@@ -0,0 +1,7 @@
1
+ dtools/circular_array/__init__.py,sha256=HLp77z9ZpK_08IeOtC5DxUzSRgOfit2uNMtN2vLPycs,1225
2
+ dtools/circular_array/ca.py,sha256=PRt-AOvR9WqwS6EdKFWXde7VxBc1yOD6kuCK_lXuWFQ,16683
3
+ dtools/circular_array/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ dtools_circular_array-3.12.0.dist-info/licenses/LICENSE,sha256=csqbZRvA3Nyuav1aszWvswE8CZtaKr-hMjjjcKqms7w,10774
5
+ dtools_circular_array-3.12.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
6
+ dtools_circular_array-3.12.0.dist-info/METADATA,sha256=5teklBZccescI4dK27U5YL7LYb7gYpKyJ8G4VkqaKhA,3495
7
+ dtools_circular_array-3.12.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- dtools/circular_array/__init__.py,sha256=-GZLNI-R4UvHgg5pLNGxdNPYO8LX4Aq6eUp9rYB3Vkg,1018
2
- dtools/circular_array/ca.py,sha256=FZe0ksC9BFzQXqqRY8YXaEpF0g38CR6-rdMOWcReKcw,16534
3
- dtools/circular_array/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- dtools_circular_array-3.10.1.dist-info/licenses/LICENSE,sha256=csqbZRvA3Nyuav1aszWvswE8CZtaKr-hMjjjcKqms7w,10774
5
- dtools_circular_array-3.10.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
6
- dtools_circular_array-3.10.1.dist-info/METADATA,sha256=49FC3FiNoCuhYf7e_gf2KNlYDYZ9Gj8m4M25g2fTCjQ,3505
7
- dtools_circular_array-3.10.1.dist-info/RECORD,,