omlish 0.0.0.dev1__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.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,127 @@
1
+ import collections.abc
2
+ import typing as ta
3
+ import weakref
4
+
5
+
6
+ T = ta.TypeVar('T')
7
+ K = ta.TypeVar('K')
8
+ V = ta.TypeVar('V')
9
+
10
+
11
+ def multikey_dict(dct: ta.Mapping[ta.Union[ta.Iterable[K], K], V], *, deep: bool = False) -> dict[K, V]:
12
+ ret = {}
13
+ for k, v in dct.items():
14
+ if deep and isinstance(v, dict):
15
+ v = multikey_dict(v, deep=True) # type: ignore
16
+ if isinstance(k, tuple):
17
+ for sk in k:
18
+ ret[sk] = v
19
+ else:
20
+ ret[k] = v
21
+ return ret
22
+
23
+
24
+ def guarded_map_update(
25
+ dst: ta.MutableMapping[ta.Any, ta.Any],
26
+ *srcs: ta.Mapping[ta.Any, ta.Any]
27
+ ) -> ta.MutableMapping[ta.Any, ta.Any]:
28
+ for src in srcs:
29
+ for k, v in src.items():
30
+ if k in dst:
31
+ raise KeyError(k)
32
+ dst[k] = v
33
+ return dst
34
+
35
+
36
+ def yield_dict_init(*args, **kwargs) -> ta.Iterable[tuple[ta.Any, ta.Any]]:
37
+ if len(args) > 1:
38
+ raise TypeError
39
+ if args:
40
+ [src] = args
41
+ if isinstance(src, collections.abc.Mapping):
42
+ for k in src:
43
+ yield (k, src[k])
44
+ else:
45
+ for k, v in src:
46
+ yield (k, v)
47
+ for k, v in kwargs.items():
48
+ yield (k, v)
49
+
50
+
51
+ class TypeMap(ta.Generic[T]):
52
+
53
+ def __init__(self, items: ta.Iterable[T] = ()) -> None:
54
+ super().__init__()
55
+
56
+ self._items = list(items)
57
+ dct: dict[type, ta.Any] = {}
58
+ for item in items:
59
+ if (ty := type(item)) in dct:
60
+ raise ValueError(ty)
61
+ dct[ty] = item
62
+ self._dct = dct
63
+
64
+ @property
65
+ def items(self) -> ta.Sequence[T]:
66
+ return self._items
67
+
68
+ def __len__(self) -> int:
69
+ return len(self._items)
70
+
71
+ def __iter__(self) -> ta.Iterable[T]:
72
+ return iter(self._items)
73
+
74
+ def get(self, ty: type[T]) -> ta.Optional[T]:
75
+ return self._dct.get(ty)
76
+
77
+ def __getitem__(self, ty: type[T]) -> ta.Sequence[T]:
78
+ return self._dct[ty]
79
+
80
+
81
+ class TypeMultiMap(ta.Generic[V]):
82
+
83
+ def __init__(self, items: ta.Iterable[V] = (), *, weak: bool = False) -> None:
84
+ super().__init__()
85
+
86
+ self._items = list(items)
87
+ self._weak = bool(weak)
88
+
89
+ self._cache: ta.MutableMapping[type, ta.Any] = weakref.WeakKeyDictionary()
90
+
91
+ @property
92
+ def items(self) -> ta.Sequence[V]:
93
+ return self._items
94
+
95
+ @property
96
+ def weak(self) -> bool:
97
+ return self._weak
98
+
99
+ def __len__(self) -> int:
100
+ return len(self._items)
101
+
102
+ def __iter__(self) -> ta.Iterable[V]:
103
+ return iter(self._items)
104
+
105
+ def __getitem__(self, ty: type[T]) -> ta.Sequence[T]:
106
+ try:
107
+ return self._cache[ty]
108
+ except KeyError:
109
+ ret = []
110
+ for item in self._items:
111
+ if isinstance(item, ty):
112
+ ret.append(item)
113
+ self._cache[ty] = ret
114
+ return ret
115
+
116
+
117
+ class MissingDict(dict[K, V]):
118
+
119
+ def __init__(self, missing_fn: ta.Callable[[K], V]) -> None:
120
+ if not callable(missing_fn):
121
+ raise TypeError(missing_fn)
122
+ super().__init__()
123
+ self._missing_fn = missing_fn
124
+
125
+ def __missing__(self, key):
126
+ v = self[key] = self._missing_fn(key)
127
+ return v
@@ -0,0 +1,81 @@
1
+ import typing as ta
2
+
3
+
4
+ T = ta.TypeVar('T')
5
+
6
+
7
+ class OrderedSet(ta.MutableSet[T]):
8
+
9
+ def __init__(self, iterable: ta.Optional[ta.Iterable[T]] = None) -> None:
10
+ super().__init__()
11
+ self._dct: dict[T, ta.Any] = {}
12
+ if iterable is not None:
13
+ self |= iterable # type: ignore # noqa
14
+
15
+ def __len__(self) -> int:
16
+ return len(self._dct)
17
+
18
+ def __contains__(self, item: ta.Any) -> bool:
19
+ return item in self._dct
20
+
21
+ def add(self, item: T) -> None:
22
+ if item not in self._dct:
23
+ self._dct[item] = None
24
+
25
+ def update(self, items: ta.Iterable[T]) -> None:
26
+ for item in items:
27
+ if item not in self._dct:
28
+ self._dct[item] = None
29
+
30
+ def discard(self, item: T) -> None:
31
+ if item in self._dct:
32
+ del self._dct[item]
33
+
34
+ def __iter__(self) -> ta.Iterator[T]:
35
+ return iter(self._dct.keys())
36
+
37
+ def __reversed__(self):
38
+ return reversed(self._dct.keys())
39
+
40
+ def pop(self, last=True):
41
+ if not self:
42
+ raise KeyError('set is empty')
43
+ item = next(reversed(self._dct.keys()))
44
+ self.discard(item)
45
+ return item
46
+
47
+ def __repr__(self):
48
+ if not self:
49
+ return '%s()' % (self.__class__.__name__,)
50
+ return '%s(%r)' % (self.__class__.__name__, list(self))
51
+
52
+ def __eq__(self, other) -> bool:
53
+ if isinstance(other, OrderedSet):
54
+ return len(self) == len(other) and list(self) == list(other)
55
+ return set(self) == set(other)
56
+
57
+
58
+ class OrderedFrozenSet(ta.FrozenSet[T]):
59
+
60
+ _list: ta.Sequence[T]
61
+
62
+ def __new__(cls, items: ta.Iterable[T]) -> ta.FrozenSet[T]: # type: ignore
63
+ item_set = set()
64
+ item_list = []
65
+ for item in items:
66
+ if item not in item_set:
67
+ item_set.add(item)
68
+ item_list.append(item)
69
+ obj = super(cls, OrderedFrozenSet).__new__(cls, item_set)
70
+ obj._list = item_list # type: ignore # noqa
71
+ return obj
72
+
73
+ def __repr__(self) -> str:
74
+ return f'{self.__class__.__name__}([{", ".join(map(repr, self))}])'
75
+
76
+ def __iter__(self) -> ta.Iterator[T]:
77
+ return iter(self._list)
78
+
79
+ def __sub__(self, other: ta.Iterable[T]) -> ta.FrozenSet[T]:
80
+ s = set(other)
81
+ return type(self)(i for i in self if i not in s)
@@ -0,0 +1,36 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+
5
+ K = ta.TypeVar('K')
6
+ V = ta.TypeVar('V')
7
+
8
+
9
+ class PersistentMap(ta.Generic[K, V], abc.ABC):
10
+ @abc.abstractmethod
11
+ def __len__(self) -> int:
12
+ raise NotImplementedError
13
+
14
+ @abc.abstractmethod
15
+ def __contains__(self, item: K) -> bool:
16
+ raise NotImplementedError
17
+
18
+ @abc.abstractmethod
19
+ def __getitem__(self, item: K) -> V:
20
+ raise NotImplementedError
21
+
22
+ @abc.abstractmethod
23
+ def __iter__(self) -> ta.Iterator[tuple[K, V]]:
24
+ raise NotImplementedError
25
+
26
+ @abc.abstractmethod
27
+ def with_(self, k: K, v: V) -> 'PersistentMap[K, V]':
28
+ raise NotImplementedError
29
+
30
+ @abc.abstractmethod
31
+ def without(self, k: K) -> 'PersistentMap[K, V]':
32
+ raise NotImplementedError
33
+
34
+ @abc.abstractmethod
35
+ def default(self, k: K, v: V) -> 'PersistentMap[K, V]':
36
+ raise NotImplementedError
@@ -0,0 +1,193 @@
1
+ import random
2
+ import typing as ta
3
+
4
+ from .sorted import SortedCollection
5
+ from .sorted import SortedListDict
6
+
7
+
8
+ T = ta.TypeVar('T')
9
+ K = ta.TypeVar('K')
10
+ V = ta.TypeVar('V')
11
+
12
+
13
+ class SkipList(SortedCollection[T]):
14
+ """https://gist.github.com/icejoywoo/3bf0c54983a725fa3917"""
15
+
16
+ class _Node:
17
+ __slots__ = [
18
+ 'value',
19
+ 'level',
20
+ 'next',
21
+ 'prev',
22
+ ]
23
+
24
+ next: list[ta.Optional['SkipList._Node']]
25
+ prev: ta.Optional['SkipList._Node']
26
+
27
+ def __init__(
28
+ self,
29
+ value: T,
30
+ level: int
31
+ ) -> None:
32
+ super().__init__()
33
+
34
+ if level <= 0:
35
+ raise TypeError('level must be > 0')
36
+
37
+ self.value = value
38
+ self.level = level
39
+ self.next = [None] * level
40
+ self.prev = None
41
+
42
+ def __repr__(self) -> str:
43
+ return f'{type(self).__name__}(value={self.value!r})'
44
+
45
+ def __init__(
46
+ self,
47
+ *,
48
+ max_height: int = 16,
49
+ comparator: ta.Optional[SortedCollection.Comparator[T]] = None,
50
+ ) -> None:
51
+ super().__init__()
52
+
53
+ if comparator is None:
54
+ comparator = SortedCollection.default_comparator
55
+ self._compare = comparator
56
+ self._max_height = max_height
57
+ self._head = SkipList._Node(None, self._max_height)
58
+ self._height = 1
59
+ self._head.next = [None] * self._max_height
60
+ self._length = 0
61
+
62
+ def __len__(self) -> int:
63
+ return self._length
64
+
65
+ def __iter__(self) -> ta.Iterator[T]:
66
+ return iter(self.iter())
67
+
68
+ def __contains__(self, value: T) -> bool: # type: ignore
69
+ return self.find(value) is not None
70
+
71
+ def _random_level(self) -> int:
72
+ result = 1
73
+ while random.uniform(0, 1) < 0.5 and result < self._max_height:
74
+ result += 1
75
+ return result
76
+
77
+ def add(self, value: T) -> bool:
78
+ if value is None:
79
+ raise TypeError(value)
80
+
81
+ node = SkipList._Node(value, self._random_level())
82
+ update = [None] * self._max_height # noqa
83
+ cur = self._head
84
+
85
+ for i in range(self._height - 1, -1, -1):
86
+ while cur.next[i] is not None and self._compare(value, cur.next[i].value) > 0: # type: ignore
87
+ cur = cur.next[i] # type: ignore
88
+ update[i] = cur # type: ignore
89
+
90
+ cur = cur.next[0] # type: ignore
91
+ if cur is not None:
92
+ if self._compare(value, cur.value) == 0: # type: ignore
93
+ return False
94
+ node.prev, cur.prev = cur.prev, node
95
+ else:
96
+ node.prev = update[0] # type: ignore
97
+
98
+ if node.level > self._height:
99
+ for i in range(self._height, node.level):
100
+ update[i] = self._head # type: ignore
101
+ self._height = node.level
102
+
103
+ for i in range(node.level):
104
+ cur = update[i] # type: ignore
105
+ node.next[i] = cur.next[i] # noqa
106
+ cur.next[i] = node # noqa
107
+
108
+ self._length += 1
109
+ return True
110
+
111
+ def _find(self, value: T) -> ta.Optional[_Node]:
112
+ if value is None:
113
+ raise TypeError(value)
114
+
115
+ cur = self._head
116
+
117
+ for i in range(self._height - 1, -1, -1):
118
+ while cur.next[i] and self._compare(value, cur.next[i].value) > 0: # type: ignore
119
+ cur = cur.next[i] # type: ignore
120
+
121
+ return cur.next[0]
122
+
123
+ def find(self, value: T) -> ta.Optional[T]:
124
+ node = self._find(value)
125
+ if node is None:
126
+ return None
127
+ if node is None or self._compare(value, node.value) != 0: # type: ignore
128
+ return None
129
+ return node.value # type: ignore
130
+
131
+ def remove(self, value: T) -> bool:
132
+ if value is None:
133
+ raise TypeError(value)
134
+
135
+ update = [None] * self._max_height # noqa
136
+ cur = self._head
137
+
138
+ for i in range(self._height - 1, -1, -1):
139
+ while cur.next[i] is not None and self._compare(value, cur.next[i].value) > 0: # type: ignore
140
+ cur = cur.next[i] # type: ignore
141
+ update[i] = cur # type: ignore
142
+
143
+ cur = cur.next[0] # type: ignore
144
+ if cur is None or self._compare(value, cur.value) != 0: # type: ignore
145
+ return False
146
+ elif cur.next[0] is not None:
147
+ cur.next[0].prev = cur.prev
148
+
149
+ for i in range(self._height):
150
+ if update[i].next[i] is not cur: # type: ignore
151
+ break
152
+ update[i].next[i] = cur.next[i] # type: ignore
153
+
154
+ while self._height > 0 and self._head.next[self._height - 1] is None:
155
+ self._height -= 1
156
+
157
+ self._length -= 1
158
+ return True
159
+
160
+ def iter(self, base: ta.Optional[T] = None) -> ta.Iterable[T]:
161
+ if base is not None:
162
+ cur = self._find(base)
163
+ while cur is not None and self._compare(base, cur.value) > 0: # type: ignore
164
+ cur = cur.next[0]
165
+ else:
166
+ cur = self._head.next[0]
167
+
168
+ while cur is not None:
169
+ yield cur.value # type: ignore
170
+ cur = cur.next[0]
171
+
172
+ def riter(self, base: ta.Optional[T] = None) -> ta.Iterable[T]:
173
+ if base is not None:
174
+ cur = self._find(base)
175
+ while cur is not self._head and self._compare(base, cur.value) < 0: # type: ignore
176
+ cur = cur.prev # type: ignore
177
+ else:
178
+ cur = self._head.next[self._height - 1]
179
+ while True:
180
+ next = cur.next[cur.next.index(None) - 1 if None in cur.next else -1] # type: ignore # noqa
181
+ if next is None:
182
+ break
183
+ cur = next
184
+
185
+ while cur is not self._head:
186
+ yield cur.value # type: ignore
187
+ cur = cur.prev # type: ignore
188
+
189
+
190
+ class SkipListDict(SortedListDict[K, V]):
191
+
192
+ def __init__(self, *args, **kwargs) -> None:
193
+ super().__init__(SkipList(comparator=SortedListDict._item_comparator), *args, **kwargs)
@@ -0,0 +1,126 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from .. import lang
5
+ from .mappings import yield_dict_init
6
+
7
+
8
+ T = ta.TypeVar('T')
9
+ U = ta.TypeVar('U')
10
+ K = ta.TypeVar('K')
11
+ V = ta.TypeVar('V')
12
+
13
+
14
+ class SortedCollection(lang.Abstract, ta.Collection[T]):
15
+
16
+ Comparator = ta.Callable[[U, U], int]
17
+
18
+ @staticmethod
19
+ def default_comparator(a: T, b: T) -> int:
20
+ """https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons"""
21
+
22
+ return (a > b) - (a < b) # type: ignore
23
+
24
+ @abc.abstractmethod
25
+ def __len__(self) -> int:
26
+ raise NotImplementedError
27
+
28
+ @abc.abstractmethod
29
+ def __iter__(self) -> ta.Iterator[T]:
30
+ raise NotImplementedError
31
+
32
+ @abc.abstractmethod
33
+ def __contains__(self, value: T) -> bool: # type: ignore
34
+ raise NotImplementedError
35
+
36
+ @abc.abstractmethod
37
+ def add(self, value: T) -> bool:
38
+ raise NotImplementedError
39
+
40
+ @abc.abstractmethod
41
+ def find(self, value: T) -> ta.Optional[T]:
42
+ raise NotImplementedError
43
+
44
+ @abc.abstractmethod
45
+ def remove(self, value: T) -> bool:
46
+ raise NotImplementedError
47
+
48
+ @abc.abstractmethod
49
+ def iter(self, base: ta.Optional[T] = None) -> ta.Iterable[T]:
50
+ raise NotImplementedError
51
+
52
+ @abc.abstractmethod
53
+ def riter(self, base: ta.Optional[T] = None) -> ta.Iterable[T]:
54
+ raise NotImplementedError
55
+
56
+
57
+ class SortedMapping(ta.Mapping[K, V]):
58
+
59
+ @abc.abstractmethod
60
+ def items(self) -> ta.Iterator[tuple[K, V]]: # type: ignore
61
+ raise NotImplementedError
62
+
63
+ @abc.abstractmethod
64
+ def ritems(self) -> ta.Iterator[tuple[K, V]]:
65
+ raise NotImplementedError
66
+
67
+ @abc.abstractmethod
68
+ def itemsfrom(self, key: K) -> ta.Iterator[tuple[K, V]]:
69
+ raise NotImplementedError
70
+
71
+ @abc.abstractmethod
72
+ def ritemsfrom(self, key: K) -> ta.Iterator[tuple[K, V]]:
73
+ raise NotImplementedError
74
+
75
+
76
+ class SortedMutableMapping(ta.MutableMapping[K, V], SortedMapping[K, V]):
77
+ pass
78
+
79
+
80
+ class SortedListDict(SortedMutableMapping[K, V]):
81
+
82
+ @staticmethod
83
+ def _item_comparator(a: tuple[K, V], b: tuple[K, V]) -> int:
84
+ return SortedCollection.default_comparator(a[0], b[0])
85
+
86
+ def __init__(self, impl: SortedCollection, *args, **kwargs) -> None:
87
+ super().__init__()
88
+ self._impl = impl
89
+ for k, v in yield_dict_init(*args, **kwargs):
90
+ self[k] = v
91
+
92
+ @property
93
+ def debug(self) -> ta.Mapping[K, V]:
94
+ return dict(self)
95
+
96
+ def __getitem__(self, key: K) -> V:
97
+ item = self._impl.find((key, None))
98
+ if item is None:
99
+ raise KeyError(key)
100
+ return item[1]
101
+
102
+ def __setitem__(self, key: K, value: V) -> None:
103
+ self._impl.remove((key, None))
104
+ self._impl.add((key, value))
105
+
106
+ def __delitem__(self, key: K) -> None:
107
+ self._impl.remove((key, None))
108
+
109
+ def __len__(self) -> int:
110
+ return len(self._impl)
111
+
112
+ def __iter__(self) -> ta.Iterator[K]:
113
+ for k, v in self._impl:
114
+ yield k
115
+
116
+ def items(self) -> ta.Iterator[tuple[K, V]]: # type: ignore
117
+ yield from self._impl.iter()
118
+
119
+ def ritems(self) -> ta.Iterator[tuple[K, V]]:
120
+ yield from self._impl.riter()
121
+
122
+ def itemsfrom(self, key: K) -> ta.Iterator[tuple[K, V]]:
123
+ yield from self._impl.iter((key, None))
124
+
125
+ def ritemsfrom(self, key: K) -> ta.Iterator[tuple[K, V]]:
126
+ yield from self._impl.riter((key, None))