|
1 | 1 | from typing import TYPE_CHECKING, Any, Union, overload |
2 | 2 | from collections.abc import Sequence |
| 3 | +from functools import lru_cache |
3 | 4 |
|
4 | 5 | if TYPE_CHECKING: |
5 | 6 | import sqlite3 |
@@ -36,6 +37,40 @@ def __repr__(self) -> str: |
36 | 37 | suffix += "[]" * (len(self._dims) - len(self._resolved_dims)) |
37 | 38 | return f"<RALArray of {obj_name}: {self._parent.path}.{self._row['name']}{suffix}>" |
38 | 39 |
|
| 40 | + @lru_cache() |
| 41 | + def _get_single_item(self, idx: int) -> "RALChild": |
| 42 | + dim = self._dims[self._this_dim_idx] |
| 43 | + |
| 44 | + if idx >= dim or idx < 0: |
| 45 | + raise IndexError("array index out of range") |
| 46 | + |
| 47 | + # Update known dimensions |
| 48 | + resolved_dims = self._resolved_dims.copy() |
| 49 | + resolved_dims.append(idx) |
| 50 | + |
| 51 | + if len(resolved_dims) != len(self._dims): |
| 52 | + # Multi-dimensional array still has unresolved dimensions |
| 53 | + # Create another array |
| 54 | + return RALArray( |
| 55 | + self._parent, |
| 56 | + self._dbapi, |
| 57 | + resolved_dims, |
| 58 | + self._dims, |
| 59 | + self._row, |
| 60 | + ) |
| 61 | + |
| 62 | + # All dimensions are known. Create the actual node |
| 63 | + flat_idx = 0 |
| 64 | + for i, current_idx in enumerate(resolved_dims): |
| 65 | + sz = 1 |
| 66 | + for j in range(i + 1, len(self._dims)): |
| 67 | + sz *= self._dims[j] |
| 68 | + flat_idx += sz * current_idx |
| 69 | + array_offset = flat_idx * self._row["stride"] |
| 70 | + |
| 71 | + array_suffix = "".join([f"[{d}]" for d in resolved_dims]) |
| 72 | + return self._dbapi.build_node(self._parent, self._row, array_suffix, array_offset) |
| 73 | + |
39 | 74 | @overload |
40 | 75 | def __getitem__(self, subscript: int) -> "RALChild": ... |
41 | 76 |
|
@@ -63,44 +98,15 @@ def __getitem__(self, subscript: Any) -> Union["RALChild", list["RALChild"]]: |
63 | 98 | # This is consistent with Python's behavior for lists |
64 | 99 | start = max(start, 0) |
65 | 100 | stop = min(stop, dim) |
66 | | - return [self[i] for i in range(start, stop, step)] |
| 101 | + return [self._get_single_item(i) for i in range(start, stop, step)] |
67 | 102 | elif not isinstance(subscript, int): |
68 | 103 | raise TypeError("array indices must be integers or slices") |
69 | 104 |
|
70 | | - |
71 | 105 | # Handle negative subscripts that index from end of array |
72 | 106 | if subscript < 0: |
73 | 107 | subscript += dim |
74 | 108 |
|
75 | | - if subscript >= dim or subscript < 0: |
76 | | - raise IndexError("array index out of range") |
77 | | - |
78 | | - # Update known dimensions |
79 | | - resolved_dims = self._resolved_dims.copy() |
80 | | - resolved_dims.append(subscript) |
81 | | - |
82 | | - if len(resolved_dims) != len(self._dims): |
83 | | - # Multi-dimensional array still has unresolved dimensions |
84 | | - # Create another array |
85 | | - return RALArray( |
86 | | - self._parent, |
87 | | - self._dbapi, |
88 | | - resolved_dims, |
89 | | - self._dims, |
90 | | - self._row, |
91 | | - ) |
92 | | - |
93 | | - # All dimensions are known. Create the actual node |
94 | | - flat_idx = 0 |
95 | | - for i, current_idx in enumerate(resolved_dims): |
96 | | - sz = 1 |
97 | | - for j in range(i + 1, len(self._dims)): |
98 | | - sz *= self._dims[j] |
99 | | - flat_idx += sz * current_idx |
100 | | - array_offset = flat_idx * self._row["stride"] |
101 | | - |
102 | | - array_suffix = "".join([f"[{d}]" for d in resolved_dims]) |
103 | | - return self._dbapi.build_node(self._parent, self._row, array_suffix, array_offset) |
| 109 | + return self._get_single_item(subscript) |
104 | 110 |
|
105 | 111 | def __len__(self) -> int: |
106 | 112 | return self._dims[self._this_dim_idx] |
0 commit comments