Skip to content

Commit 40b529c

Browse files
committed
feat(internal[sparse_array]): Add SparseArray
1 parent 7c11e71 commit 40b529c

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/libtmux/_internal/sparse_array.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Sparse array for libtmux options and hooks."""
2+
3+
from __future__ import annotations
4+
5+
import typing as t
6+
7+
if t.TYPE_CHECKING:
8+
from typing_extensions import TypeAlias, TypeGuard
9+
10+
from libtmux.options import ExplodedComplexUntypedOptionsDict
11+
12+
13+
T = t.TypeVar("T")
14+
HookArray: TypeAlias = "dict[str, SparseArray[str]]"
15+
16+
17+
def is_sparse_array_list(
18+
items: ExplodedComplexUntypedOptionsDict,
19+
) -> TypeGuard[HookArray]:
20+
return all(
21+
isinstance(
22+
v,
23+
SparseArray,
24+
)
25+
for k, v in items.items()
26+
)
27+
28+
29+
class SparseArray(dict[int, T], t.Generic[T]):
30+
"""Support non-sequential indexes while maintaining :class:`list`-like behavior.
31+
32+
A normal :class:`list` would raise :exc:`IndexError`.
33+
34+
There are no native sparse arrays in python that contain non-sequential indexes and
35+
maintain list-like behavior. This is useful for handling libtmux options and hooks:
36+
37+
``command-alias[1] split-pane=split-window`` to
38+
``{'command-alias[1]': {'split-pane=split-window'}}``
39+
40+
:class:`list` would lose indice info, and :class:`dict` would lose list-like
41+
behavior.
42+
"""
43+
44+
def add(self, index: int, value: T) -> None:
45+
self[index] = value
46+
47+
def append(self, value: T) -> None:
48+
index = max(self.keys()) + 1
49+
self[index] = value
50+
51+
def iter_values(self) -> t.Iterator[T]:
52+
for index in sorted(self.keys()):
53+
yield self[index]
54+
55+
def as_list(self) -> list[T]:
56+
return [self[index] for index in sorted(self.keys())]

0 commit comments

Comments
 (0)