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.
- omlish/__about__.py +7 -0
- omlish/__init__.py +0 -0
- omlish/argparse.py +223 -0
- omlish/asyncs/__init__.py +17 -0
- omlish/asyncs/anyio.py +23 -0
- omlish/asyncs/asyncio.py +19 -0
- omlish/asyncs/asyncs.py +76 -0
- omlish/asyncs/futures.py +179 -0
- omlish/asyncs/trio.py +11 -0
- omlish/c3.py +173 -0
- omlish/cached.py +9 -0
- omlish/check.py +231 -0
- omlish/collections/__init__.py +63 -0
- omlish/collections/_abc.py +156 -0
- omlish/collections/_io_abc.py +78 -0
- omlish/collections/cache/__init__.py +11 -0
- omlish/collections/cache/descriptor.py +188 -0
- omlish/collections/cache/impl.py +485 -0
- omlish/collections/cache/types.py +37 -0
- omlish/collections/coerce.py +337 -0
- omlish/collections/frozen.py +148 -0
- omlish/collections/identity.py +106 -0
- omlish/collections/indexed.py +75 -0
- omlish/collections/mappings.py +127 -0
- omlish/collections/ordered.py +81 -0
- omlish/collections/persistent.py +36 -0
- omlish/collections/skiplist.py +193 -0
- omlish/collections/sorted.py +126 -0
- omlish/collections/treap.py +228 -0
- omlish/collections/treapmap.py +144 -0
- omlish/collections/unmodifiable.py +174 -0
- omlish/collections/utils.py +110 -0
- omlish/configs/__init__.py +0 -0
- omlish/configs/flattening.py +147 -0
- omlish/configs/props.py +64 -0
- omlish/dataclasses/__init__.py +83 -0
- omlish/dataclasses/impl/__init__.py +6 -0
- omlish/dataclasses/impl/api.py +260 -0
- omlish/dataclasses/impl/as_.py +76 -0
- omlish/dataclasses/impl/exceptions.py +2 -0
- omlish/dataclasses/impl/fields.py +148 -0
- omlish/dataclasses/impl/frozen.py +55 -0
- omlish/dataclasses/impl/hashing.py +85 -0
- omlish/dataclasses/impl/init.py +173 -0
- omlish/dataclasses/impl/internals.py +118 -0
- omlish/dataclasses/impl/main.py +150 -0
- omlish/dataclasses/impl/metaclass.py +126 -0
- omlish/dataclasses/impl/metadata.py +74 -0
- omlish/dataclasses/impl/order.py +47 -0
- omlish/dataclasses/impl/params.py +150 -0
- omlish/dataclasses/impl/processing.py +16 -0
- omlish/dataclasses/impl/reflect.py +173 -0
- omlish/dataclasses/impl/replace.py +40 -0
- omlish/dataclasses/impl/repr.py +34 -0
- omlish/dataclasses/impl/simple.py +92 -0
- omlish/dataclasses/impl/slots.py +80 -0
- omlish/dataclasses/impl/utils.py +167 -0
- omlish/defs.py +193 -0
- omlish/dispatch/__init__.py +3 -0
- omlish/dispatch/dispatch.py +137 -0
- omlish/dispatch/functions.py +52 -0
- omlish/dispatch/methods.py +162 -0
- omlish/docker.py +149 -0
- omlish/dynamic.py +220 -0
- omlish/graphs/__init__.py +0 -0
- omlish/graphs/dot/__init__.py +19 -0
- omlish/graphs/dot/items.py +162 -0
- omlish/graphs/dot/rendering.py +147 -0
- omlish/graphs/dot/utils.py +30 -0
- omlish/graphs/trees.py +249 -0
- omlish/http/__init__.py +0 -0
- omlish/http/consts.py +20 -0
- omlish/http/wsgi.py +34 -0
- omlish/inject/__init__.py +85 -0
- omlish/inject/binder.py +12 -0
- omlish/inject/bindings.py +49 -0
- omlish/inject/eagers.py +21 -0
- omlish/inject/elements.py +43 -0
- omlish/inject/exceptions.py +49 -0
- omlish/inject/impl/__init__.py +0 -0
- omlish/inject/impl/bindings.py +19 -0
- omlish/inject/impl/elements.py +154 -0
- omlish/inject/impl/injector.py +182 -0
- omlish/inject/impl/inspect.py +98 -0
- omlish/inject/impl/private.py +109 -0
- omlish/inject/impl/providers.py +132 -0
- omlish/inject/impl/scopes.py +198 -0
- omlish/inject/injector.py +40 -0
- omlish/inject/inspect.py +14 -0
- omlish/inject/keys.py +43 -0
- omlish/inject/managed.py +24 -0
- omlish/inject/overrides.py +18 -0
- omlish/inject/private.py +29 -0
- omlish/inject/providers.py +111 -0
- omlish/inject/proxy.py +48 -0
- omlish/inject/scopes.py +84 -0
- omlish/inject/types.py +21 -0
- omlish/iterators.py +184 -0
- omlish/json.py +194 -0
- omlish/lang/__init__.py +112 -0
- omlish/lang/cached.py +267 -0
- omlish/lang/classes/__init__.py +24 -0
- omlish/lang/classes/abstract.py +74 -0
- omlish/lang/classes/restrict.py +137 -0
- omlish/lang/classes/simple.py +120 -0
- omlish/lang/classes/test/__init__.py +0 -0
- omlish/lang/classes/test/test_abstract.py +89 -0
- omlish/lang/classes/test/test_restrict.py +71 -0
- omlish/lang/classes/test/test_simple.py +58 -0
- omlish/lang/classes/test/test_virtual.py +72 -0
- omlish/lang/classes/virtual.py +130 -0
- omlish/lang/clsdct.py +67 -0
- omlish/lang/cmp.py +63 -0
- omlish/lang/contextmanagers.py +249 -0
- omlish/lang/datetimes.py +67 -0
- omlish/lang/descriptors.py +52 -0
- omlish/lang/functions.py +126 -0
- omlish/lang/imports.py +153 -0
- omlish/lang/iterables.py +54 -0
- omlish/lang/maybes.py +136 -0
- omlish/lang/objects.py +103 -0
- omlish/lang/resolving.py +50 -0
- omlish/lang/strings.py +128 -0
- omlish/lang/typing.py +92 -0
- omlish/libc.py +532 -0
- omlish/logs/__init__.py +9 -0
- omlish/logs/_abc.py +247 -0
- omlish/logs/configs.py +62 -0
- omlish/logs/filters.py +9 -0
- omlish/logs/formatters.py +67 -0
- omlish/logs/utils.py +20 -0
- omlish/marshal/__init__.py +52 -0
- omlish/marshal/any.py +25 -0
- omlish/marshal/base.py +201 -0
- omlish/marshal/base64.py +25 -0
- omlish/marshal/dataclasses.py +115 -0
- omlish/marshal/datetimes.py +90 -0
- omlish/marshal/enums.py +43 -0
- omlish/marshal/exceptions.py +7 -0
- omlish/marshal/factories.py +129 -0
- omlish/marshal/global_.py +33 -0
- omlish/marshal/iterables.py +57 -0
- omlish/marshal/mappings.py +66 -0
- omlish/marshal/naming.py +17 -0
- omlish/marshal/objects.py +106 -0
- omlish/marshal/optionals.py +49 -0
- omlish/marshal/polymorphism.py +147 -0
- omlish/marshal/primitives.py +43 -0
- omlish/marshal/registries.py +57 -0
- omlish/marshal/standard.py +80 -0
- omlish/marshal/utils.py +23 -0
- omlish/marshal/uuids.py +29 -0
- omlish/marshal/values.py +30 -0
- omlish/math.py +184 -0
- omlish/os.py +32 -0
- omlish/reflect.py +359 -0
- omlish/replserver/__init__.py +5 -0
- omlish/replserver/__main__.py +4 -0
- omlish/replserver/console.py +247 -0
- omlish/replserver/server.py +146 -0
- omlish/runmodule.py +28 -0
- omlish/stats.py +342 -0
- omlish/term.py +222 -0
- omlish/testing/__init__.py +7 -0
- omlish/testing/pydevd.py +225 -0
- omlish/testing/pytest/__init__.py +8 -0
- omlish/testing/pytest/helpers.py +35 -0
- omlish/testing/pytest/inject/__init__.py +1 -0
- omlish/testing/pytest/inject/harness.py +159 -0
- omlish/testing/pytest/plugins/__init__.py +20 -0
- omlish/testing/pytest/plugins/_registry.py +6 -0
- omlish/testing/pytest/plugins/logging.py +13 -0
- omlish/testing/pytest/plugins/pycharm.py +54 -0
- omlish/testing/pytest/plugins/repeat.py +19 -0
- omlish/testing/pytest/plugins/skips.py +32 -0
- omlish/testing/pytest/plugins/spacing.py +19 -0
- omlish/testing/pytest/plugins/switches.py +70 -0
- omlish/testing/testing.py +102 -0
- omlish/text/__init__.py +0 -0
- omlish/text/delimit.py +171 -0
- omlish/text/indent.py +50 -0
- omlish/text/parts.py +265 -0
- omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
- omlish-0.0.0.dev1.dist-info/METADATA +17 -0
- omlish-0.0.0.dev1.dist-info/RECORD +187 -0
- omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
- omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2022 Gabriel Ochsenhofer
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
7
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
8
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
9
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
12
|
+
Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
15
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
17
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
18
|
+
"""
|
|
19
|
+
import typing as ta
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
T = ta.TypeVar('T')
|
|
23
|
+
Comparer = ta.Callable[[T, T], int]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TreapNode(ta.Generic[T]):
|
|
27
|
+
__slots__ = ('_value', '_priority', '_left', '_right')
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
_value: T,
|
|
33
|
+
_priority: int,
|
|
34
|
+
_left: ta.Optional['TreapNode[T]'],
|
|
35
|
+
_right: ta.Optional['TreapNode[T]'],
|
|
36
|
+
) -> None:
|
|
37
|
+
super().__init__()
|
|
38
|
+
|
|
39
|
+
self._value = _value
|
|
40
|
+
self._priority = _priority
|
|
41
|
+
self._left = _left
|
|
42
|
+
self._right = _right
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def value(self) -> T:
|
|
46
|
+
return self._value
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def priority(self) -> int:
|
|
50
|
+
return self._priority
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def left(self) -> ta.Optional['TreapNode[T]']:
|
|
54
|
+
return self._left
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def right(self) -> ta.Optional['TreapNode[T]']:
|
|
58
|
+
return self._right
|
|
59
|
+
|
|
60
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
61
|
+
if self._left is not None:
|
|
62
|
+
yield from self._left
|
|
63
|
+
yield self._value
|
|
64
|
+
if self._right is not None:
|
|
65
|
+
yield from self._right
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def find(n: ta.Optional[TreapNode[T]], v: T, c: Comparer[T]) -> ta.Optional[TreapNode[T]]:
|
|
69
|
+
while True:
|
|
70
|
+
if n is None:
|
|
71
|
+
return None
|
|
72
|
+
diff = c(n._value, v) # noqa
|
|
73
|
+
if diff == 0:
|
|
74
|
+
return n
|
|
75
|
+
elif diff < 0:
|
|
76
|
+
n = n._right # noqa
|
|
77
|
+
else:
|
|
78
|
+
n = n._left # noqa
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def union(
|
|
82
|
+
n: ta.Optional[TreapNode[T]],
|
|
83
|
+
other: ta.Optional[TreapNode[T]],
|
|
84
|
+
c: Comparer[T],
|
|
85
|
+
overwrite: bool,
|
|
86
|
+
) -> ta.Optional[TreapNode[T]]:
|
|
87
|
+
if n is None:
|
|
88
|
+
return other
|
|
89
|
+
if other is None:
|
|
90
|
+
return n
|
|
91
|
+
if n._priority < other._priority:
|
|
92
|
+
other, n, overwrite = n, other, not overwrite
|
|
93
|
+
left, dupe, right = split(other, n._value, c)
|
|
94
|
+
value = n._value
|
|
95
|
+
if overwrite and dupe is not None:
|
|
96
|
+
value = dupe._value
|
|
97
|
+
left = union(n._left, left, c, overwrite)
|
|
98
|
+
right = union(n._right, right, c, overwrite)
|
|
99
|
+
return TreapNode(_value=value, _priority=n._priority, _left=left, _right=right)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def split(
|
|
103
|
+
n: ta.Optional[TreapNode[T]],
|
|
104
|
+
v: T,
|
|
105
|
+
c: Comparer[T],
|
|
106
|
+
) -> tuple[
|
|
107
|
+
ta.Optional[TreapNode[T]],
|
|
108
|
+
ta.Optional[TreapNode[T]],
|
|
109
|
+
ta.Optional[TreapNode[T]],
|
|
110
|
+
]:
|
|
111
|
+
tmp: TreapNode[T] = TreapNode(_value=None, _priority=0, _left=None, _right=None) # type: ignore
|
|
112
|
+
leftp, rightp = [tmp, 'l'], [tmp, 'r']
|
|
113
|
+
|
|
114
|
+
def setp(p, o):
|
|
115
|
+
t, s = p
|
|
116
|
+
if s == 'l':
|
|
117
|
+
t._left = o
|
|
118
|
+
elif s == 'r':
|
|
119
|
+
t._right = o
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError(p)
|
|
122
|
+
|
|
123
|
+
cur: ta.Optional[TreapNode[T]] = n
|
|
124
|
+
while True:
|
|
125
|
+
if cur is None:
|
|
126
|
+
setp(leftp, None)
|
|
127
|
+
setp(rightp, None)
|
|
128
|
+
return tmp._left, None, tmp._right # noqa
|
|
129
|
+
|
|
130
|
+
d = c(cur._value, v)
|
|
131
|
+
if d < 0:
|
|
132
|
+
root = TreapNode(_value=cur._value, _priority=cur._priority, _left=cur._left, _right=None)
|
|
133
|
+
setp(leftp, root)
|
|
134
|
+
leftp[0], leftp[1] = root, 'r'
|
|
135
|
+
cur = cur._right
|
|
136
|
+
elif d > 0:
|
|
137
|
+
root = TreapNode(_value=cur._value, _priority=cur._priority, _left=None, _right=cur._right)
|
|
138
|
+
setp(rightp, root)
|
|
139
|
+
rightp[0], rightp[1] = root, 'l'
|
|
140
|
+
cur = cur._left
|
|
141
|
+
else:
|
|
142
|
+
root = TreapNode(_value=cur._value, _priority=cur._priority, _left=None, _right=None)
|
|
143
|
+
setp(leftp, cur._left)
|
|
144
|
+
setp(rightp, cur._right)
|
|
145
|
+
return tmp._left, root, tmp._right
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def intersect(
|
|
149
|
+
n: ta.Optional[TreapNode[T]],
|
|
150
|
+
other: ta.Optional[TreapNode[T]],
|
|
151
|
+
c: Comparer[T],
|
|
152
|
+
) -> ta.Optional[TreapNode[T]]:
|
|
153
|
+
if n is None or other is None:
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
if n._priority < other._priority:
|
|
157
|
+
n, other = other, n
|
|
158
|
+
|
|
159
|
+
left, found, right = split(other, n._value, c)
|
|
160
|
+
left = intersect(n._left, left, c)
|
|
161
|
+
right = intersect(n._right, right, c)
|
|
162
|
+
|
|
163
|
+
if found is None:
|
|
164
|
+
# TODO: use a destructive join as both left/right are copies
|
|
165
|
+
return _join(left, right)
|
|
166
|
+
|
|
167
|
+
return TreapNode(_value=n._value, _priority=n._priority, _left=left, _right=right)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def delete(n: ta.Optional[TreapNode[T]], v: T, c: Comparer[T]) -> ta.Optional[TreapNode[T]]:
|
|
171
|
+
left, _, right = split(n, v, c)
|
|
172
|
+
return _join(left, right)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def diff(n: ta.Optional[TreapNode[T]], other: ta.Optional[TreapNode[T]], c: Comparer[T]) -> ta.Optional[TreapNode[T]]:
|
|
176
|
+
if n is None or other is None:
|
|
177
|
+
return n
|
|
178
|
+
|
|
179
|
+
# TODO -- use count
|
|
180
|
+
if n._priority >= other._priority:
|
|
181
|
+
left, dupe, right = split(other, n._value, c)
|
|
182
|
+
left, right = diff(n._left, left, c), diff(n._right, right, c)
|
|
183
|
+
if dupe is not None:
|
|
184
|
+
return _join(left, right)
|
|
185
|
+
return TreapNode(_value=n._value, _priority=n._priority, _left=left, _right=right)
|
|
186
|
+
|
|
187
|
+
left, _, right = split(n, other._value, c)
|
|
188
|
+
left = diff(left, other._left, c)
|
|
189
|
+
right = diff(right, other._right, c)
|
|
190
|
+
return _join(left, right)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _join(n: ta.Optional[TreapNode[T]], other: ta.Optional[TreapNode[T]]) -> ta.Optional[TreapNode[T]]:
|
|
194
|
+
result: ta.Optional[TreapNode[T]] = None
|
|
195
|
+
resultp: list[ta.Any] = [None, None]
|
|
196
|
+
|
|
197
|
+
def setresultp(o):
|
|
198
|
+
t, s = resultp
|
|
199
|
+
if t is None:
|
|
200
|
+
nonlocal result
|
|
201
|
+
result = o
|
|
202
|
+
elif s == 'l':
|
|
203
|
+
t._left = o
|
|
204
|
+
elif s == 'r':
|
|
205
|
+
t._right = o
|
|
206
|
+
else:
|
|
207
|
+
raise ValueError(resultp)
|
|
208
|
+
|
|
209
|
+
cur: ta.Optional[TreapNode[T]] = n
|
|
210
|
+
while True:
|
|
211
|
+
if cur is None:
|
|
212
|
+
setresultp(other)
|
|
213
|
+
return result
|
|
214
|
+
|
|
215
|
+
if other is None:
|
|
216
|
+
setresultp(cur)
|
|
217
|
+
return result
|
|
218
|
+
|
|
219
|
+
if cur._priority <= other._priority:
|
|
220
|
+
root = TreapNode(_value=cur._value, _priority=cur._priority, _left=cur._left, _right=None)
|
|
221
|
+
setresultp(root)
|
|
222
|
+
resultp[0], resultp[1] = root, 'r'
|
|
223
|
+
cur = cur._right
|
|
224
|
+
else:
|
|
225
|
+
root = TreapNode(_value=other._value, _priority=other._priority, _left=None, _right=other._right)
|
|
226
|
+
setresultp(root)
|
|
227
|
+
resultp[0], resultp[1] = root, 'l'
|
|
228
|
+
other = other._left
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2022 Gabriel Ochsenhofer
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
7
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
8
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
9
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
12
|
+
Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
15
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
17
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
18
|
+
"""
|
|
19
|
+
import random
|
|
20
|
+
import typing as ta
|
|
21
|
+
|
|
22
|
+
from . import treap
|
|
23
|
+
from .persistent import PersistentMap
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
K = ta.TypeVar('K')
|
|
27
|
+
V = ta.TypeVar('V')
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TreapMap(PersistentMap[K, V]):
|
|
31
|
+
__slots__ = ('_n', '_c')
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
*,
|
|
36
|
+
_n: ta.Optional[treap.TreapNode[tuple[K, V]]],
|
|
37
|
+
_c: treap.Comparer[tuple[K, V]],
|
|
38
|
+
) -> None:
|
|
39
|
+
super().__init__()
|
|
40
|
+
|
|
41
|
+
self._n = _n
|
|
42
|
+
self._c = _c
|
|
43
|
+
|
|
44
|
+
def __len__(self) -> int:
|
|
45
|
+
# TODO: memo
|
|
46
|
+
# TODO: itertools lol
|
|
47
|
+
if self._n is None:
|
|
48
|
+
return 0
|
|
49
|
+
result = 0
|
|
50
|
+
for _ in self._n:
|
|
51
|
+
result += 1
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
def __contains__(self, item: K) -> bool:
|
|
55
|
+
try:
|
|
56
|
+
self[item] # noqa
|
|
57
|
+
except KeyError:
|
|
58
|
+
return False
|
|
59
|
+
else:
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
def __getitem__(self, item: K) -> V:
|
|
63
|
+
n = treap.find(self._n, (item, None), self._c) # type: ignore
|
|
64
|
+
if n is None:
|
|
65
|
+
raise KeyError(item)
|
|
66
|
+
return n.value
|
|
67
|
+
|
|
68
|
+
def __iter__(self) -> ta.Iterator[tuple[K, V]]:
|
|
69
|
+
i = self.iterate()
|
|
70
|
+
while i.has_next():
|
|
71
|
+
yield i.next()
|
|
72
|
+
|
|
73
|
+
def iterate(self) -> 'TreapMapIterator[K, V]':
|
|
74
|
+
i = TreapMapIterator(
|
|
75
|
+
_st=[],
|
|
76
|
+
_n=self._n,
|
|
77
|
+
_b=False,
|
|
78
|
+
)
|
|
79
|
+
while (n := i._n) is not None and n.left is not None: # noqa
|
|
80
|
+
i._st.append(n) # noqa
|
|
81
|
+
i._n = n.left # noqa
|
|
82
|
+
return i
|
|
83
|
+
|
|
84
|
+
def with_(self, k: K, v: V) -> 'TreapMap[K, V]':
|
|
85
|
+
node = treap.TreapNode(
|
|
86
|
+
_value=(k, v),
|
|
87
|
+
_priority=int(random.random() * 0xFFFFFFFF),
|
|
88
|
+
_left=None,
|
|
89
|
+
_right=None,
|
|
90
|
+
)
|
|
91
|
+
n = treap.union(self._n, node, self._c, True)
|
|
92
|
+
return TreapMap(_n=n, _c=self._c)
|
|
93
|
+
|
|
94
|
+
def without(self, k: K) -> 'TreapMap[K, V]':
|
|
95
|
+
n = treap.delete(self._n, (k, None), self._c) # type: ignore
|
|
96
|
+
return TreapMap(_n=n, _c=self._c)
|
|
97
|
+
|
|
98
|
+
def default(self, k: K, v: V) -> 'TreapMap[K, V]':
|
|
99
|
+
try:
|
|
100
|
+
self[k] # noqa
|
|
101
|
+
except KeyError:
|
|
102
|
+
return self.with_(k, v)
|
|
103
|
+
else:
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def new_treap_map(cmp: ta.Callable[[tuple[K, V], tuple[K, V]], int]) -> PersistentMap[K, V]:
|
|
108
|
+
return TreapMap(_n=None, _c=cmp)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class TreapMapIterator(ta.Generic[K, V]):
|
|
112
|
+
__slots__ = ('_st', '_n', '_b')
|
|
113
|
+
|
|
114
|
+
def __init__(
|
|
115
|
+
self,
|
|
116
|
+
*,
|
|
117
|
+
_st: list[treap.TreapNode[tuple[K, V]]],
|
|
118
|
+
_n: ta.Optional[treap.TreapNode[tuple[K, V]]],
|
|
119
|
+
_b: bool,
|
|
120
|
+
) -> None:
|
|
121
|
+
super().__init__()
|
|
122
|
+
|
|
123
|
+
self._st = _st
|
|
124
|
+
self._n = _n
|
|
125
|
+
self._b = _b
|
|
126
|
+
|
|
127
|
+
def has_next(self) -> bool:
|
|
128
|
+
return self._n is not None
|
|
129
|
+
|
|
130
|
+
def next(self) -> tuple[K, V]:
|
|
131
|
+
n = self._n
|
|
132
|
+
if n is None:
|
|
133
|
+
raise StopIteration
|
|
134
|
+
if n.right is not None:
|
|
135
|
+
self._n = n.right
|
|
136
|
+
while self._n.left is not None:
|
|
137
|
+
self._st.append(self._n)
|
|
138
|
+
self._n = self._n.left
|
|
139
|
+
elif len(self._st) > 0:
|
|
140
|
+
self._n = self._st[-1]
|
|
141
|
+
self._st.pop()
|
|
142
|
+
else:
|
|
143
|
+
self._n = None
|
|
144
|
+
return n.value
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import lang
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
T = ta.TypeVar('T')
|
|
7
|
+
K = ta.TypeVar('K')
|
|
8
|
+
V = ta.TypeVar('V')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Unmodifiable(lang.Abstract):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class UnmodifiableSequence(ta.Sequence[T], Unmodifiable, lang.Final):
|
|
16
|
+
|
|
17
|
+
def __init__(self, target: ta.Sequence[T]) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
if target is None:
|
|
21
|
+
raise TypeError(target)
|
|
22
|
+
self._target = target
|
|
23
|
+
|
|
24
|
+
def __repr__(self) -> str:
|
|
25
|
+
return '%s(%r)' % (type(self).__name__, self._target)
|
|
26
|
+
|
|
27
|
+
def __contains__(self, x: object) -> bool:
|
|
28
|
+
return x in self._target
|
|
29
|
+
|
|
30
|
+
def __eq__(self, o: object) -> bool:
|
|
31
|
+
return self._target == o
|
|
32
|
+
|
|
33
|
+
def __ge__(self, other: object) -> bool:
|
|
34
|
+
return self._target >= other # type: ignore
|
|
35
|
+
|
|
36
|
+
def __getitem__(self, i: ta.Union[int, slice]) -> T: # type: ignore
|
|
37
|
+
return self._target[i] # type: ignore
|
|
38
|
+
|
|
39
|
+
def __gt__(self, other: object) -> bool:
|
|
40
|
+
return self._target > other # type: ignore
|
|
41
|
+
|
|
42
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
43
|
+
return iter(self._target)
|
|
44
|
+
|
|
45
|
+
def __le__(self, other: object) -> bool:
|
|
46
|
+
return self._target <= other # type: ignore
|
|
47
|
+
|
|
48
|
+
def __len__(self) -> int:
|
|
49
|
+
return len(self._target)
|
|
50
|
+
|
|
51
|
+
def __lt__(self, other: object) -> bool:
|
|
52
|
+
return self._target < other # type: ignore
|
|
53
|
+
|
|
54
|
+
def __ne__(self, o: object) -> bool:
|
|
55
|
+
return self._target != o
|
|
56
|
+
|
|
57
|
+
def __reversed__(self) -> ta.Iterator[T]:
|
|
58
|
+
return reversed(self._target)
|
|
59
|
+
|
|
60
|
+
def count(self, x: ta.Any) -> int:
|
|
61
|
+
return self._target.count(x)
|
|
62
|
+
|
|
63
|
+
def index(self, x: ta.Any, *args, **kwargs) -> int: # type: ignore
|
|
64
|
+
return self._target.index(x, *args, **kwargs)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class UnmodifiableSet(ta.AbstractSet[T], Unmodifiable, lang.Final):
|
|
68
|
+
|
|
69
|
+
def __init__(self, target: ta.AbstractSet[T]) -> None:
|
|
70
|
+
super().__init__()
|
|
71
|
+
|
|
72
|
+
if target is None:
|
|
73
|
+
raise TypeError(target)
|
|
74
|
+
self._target = target
|
|
75
|
+
|
|
76
|
+
def __repr__(self) -> str:
|
|
77
|
+
return '%s(%r)' % (type(self).__name__, self._target)
|
|
78
|
+
|
|
79
|
+
def __and__(self, s: ta.AbstractSet[ta.Any]) -> ta.AbstractSet[T]:
|
|
80
|
+
return self._target & s
|
|
81
|
+
|
|
82
|
+
def __contains__(self, x: object) -> bool:
|
|
83
|
+
return x in self._target
|
|
84
|
+
|
|
85
|
+
def __eq__(self, o: object) -> bool:
|
|
86
|
+
return self._target == o
|
|
87
|
+
|
|
88
|
+
def __ge__(self, s: ta.AbstractSet[ta.Any]) -> bool:
|
|
89
|
+
return self._target >= s
|
|
90
|
+
|
|
91
|
+
def __gt__(self, s: ta.AbstractSet[ta.Any]) -> bool:
|
|
92
|
+
return self._target > s
|
|
93
|
+
|
|
94
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
95
|
+
return iter(self._target)
|
|
96
|
+
|
|
97
|
+
def __le__(self, s: ta.AbstractSet[ta.Any]) -> bool:
|
|
98
|
+
return self._target <= s
|
|
99
|
+
|
|
100
|
+
def __len__(self) -> int:
|
|
101
|
+
return len(self._target)
|
|
102
|
+
|
|
103
|
+
def __lt__(self, s: ta.AbstractSet[ta.Any]) -> bool:
|
|
104
|
+
return self._target > s
|
|
105
|
+
|
|
106
|
+
def __ne__(self, o: object) -> bool:
|
|
107
|
+
return self._target != o
|
|
108
|
+
|
|
109
|
+
def __or__(self, s: ta.AbstractSet[T]) -> ta.AbstractSet[T]: # type: ignore
|
|
110
|
+
return self._target | s
|
|
111
|
+
|
|
112
|
+
def __sub__(self, s: ta.AbstractSet[ta.Any]) -> ta.AbstractSet[T]:
|
|
113
|
+
return self._target - s
|
|
114
|
+
|
|
115
|
+
def __xor__(self, s: ta.AbstractSet[T]) -> ta.AbstractSet[T]: # type: ignore
|
|
116
|
+
return self._target ^ s
|
|
117
|
+
|
|
118
|
+
def isdisjoint(self, s: ta.Iterable[ta.Any]) -> bool:
|
|
119
|
+
return self._target.isdisjoint(s)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class UnmodifiableMapping(ta.Mapping[K, V], Unmodifiable, lang.Final):
|
|
123
|
+
|
|
124
|
+
def __init__(self, target: ta.Mapping[K, V]) -> None:
|
|
125
|
+
super().__init__()
|
|
126
|
+
|
|
127
|
+
if target is None:
|
|
128
|
+
raise TypeError(target)
|
|
129
|
+
self._target = target
|
|
130
|
+
|
|
131
|
+
def __repr__(self) -> str:
|
|
132
|
+
return '%s(%r)' % (type(self).__name__, self._target)
|
|
133
|
+
|
|
134
|
+
def __contains__(self, o: object) -> bool:
|
|
135
|
+
return o in self._target
|
|
136
|
+
|
|
137
|
+
def __eq__(self, o: object) -> bool:
|
|
138
|
+
return self._target == o
|
|
139
|
+
|
|
140
|
+
def __ge__(self, other: object) -> bool:
|
|
141
|
+
return self._target >= other # type: ignore
|
|
142
|
+
|
|
143
|
+
def __getitem__(self, k: K) -> V:
|
|
144
|
+
return self._target[k]
|
|
145
|
+
|
|
146
|
+
def __gt__(self, other: object) -> bool:
|
|
147
|
+
return self._target > other # type: ignore
|
|
148
|
+
|
|
149
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
150
|
+
return iter(self._target) # type: ignore
|
|
151
|
+
|
|
152
|
+
def __le__(self, other: object) -> bool:
|
|
153
|
+
return self._target <= other # type: ignore
|
|
154
|
+
|
|
155
|
+
def __len__(self) -> int:
|
|
156
|
+
return len(self._target)
|
|
157
|
+
|
|
158
|
+
def __lt__(self, other: object) -> bool:
|
|
159
|
+
return self._target < other # type: ignore
|
|
160
|
+
|
|
161
|
+
def __ne__(self, o: object) -> bool:
|
|
162
|
+
return self._target != o
|
|
163
|
+
|
|
164
|
+
def get(self, k: K, default=None) -> ta.Optional[V]: # type: ignore
|
|
165
|
+
return self._target.get(k)
|
|
166
|
+
|
|
167
|
+
def items(self) -> ta.ItemsView[K, V]:
|
|
168
|
+
return self._target.items()
|
|
169
|
+
|
|
170
|
+
def keys(self) -> ta.KeysView[K]:
|
|
171
|
+
return self._target.keys()
|
|
172
|
+
|
|
173
|
+
def values(self) -> ta.ValuesView[V]:
|
|
174
|
+
return self._target.values()
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import itertools
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from .. import check
|
|
6
|
+
from .identity import IdentityKeyDict
|
|
7
|
+
from .identity import IdentitySet
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
T = ta.TypeVar('T')
|
|
11
|
+
K = ta.TypeVar('K')
|
|
12
|
+
V = ta.TypeVar('V')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def mut_toposort(data: dict[T, set[T]]) -> ta.Iterator[set[T]]:
|
|
16
|
+
for k, v in data.items():
|
|
17
|
+
v.discard(k)
|
|
18
|
+
extra_items_in_deps = functools.reduce(set.union, data.values()) - set(data.keys())
|
|
19
|
+
data.update({item: set() for item in extra_items_in_deps})
|
|
20
|
+
while True:
|
|
21
|
+
ordered = set(item for item, dep in data.items() if not dep)
|
|
22
|
+
if not ordered:
|
|
23
|
+
break
|
|
24
|
+
yield ordered
|
|
25
|
+
data = {item: (dep - ordered) for item, dep in data.items() if item not in ordered}
|
|
26
|
+
if data:
|
|
27
|
+
raise ValueError('Cyclic dependencies exist among these items: ' + ' '.join(repr(x) for x in data.items()))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def toposort(data: ta.Mapping[T, ta.AbstractSet[T]]) -> ta.Iterator[set[T]]:
|
|
31
|
+
return mut_toposort({k: set(v) for k, v in data.items()})
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def partition(items: ta.Iterable[T], pred: ta.Callable[[T], bool]) -> tuple[list[T], list[T]]:
|
|
35
|
+
t: list[T] = []
|
|
36
|
+
f: list[T] = []
|
|
37
|
+
for e in items:
|
|
38
|
+
if pred(e):
|
|
39
|
+
t.append(e)
|
|
40
|
+
else:
|
|
41
|
+
f.append(e)
|
|
42
|
+
return t, f
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def unique(it: ta.Iterable[T], *, identity: bool = False) -> list[T]:
|
|
46
|
+
if isinstance(it, str):
|
|
47
|
+
raise TypeError(it)
|
|
48
|
+
ret: list[T] = []
|
|
49
|
+
seen: ta.MutableSet[T] = IdentitySet() if identity else set()
|
|
50
|
+
for e in it:
|
|
51
|
+
if e not in seen:
|
|
52
|
+
seen.add(e)
|
|
53
|
+
ret.append(e)
|
|
54
|
+
return ret
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def unique_dict(items: ta.Iterable[tuple[K, V]], *, identity: bool = False) -> ta.MutableMapping[K, V]:
|
|
58
|
+
dct: ta.MutableMapping[K, V] = IdentityKeyDict() if identity else {}
|
|
59
|
+
for k, v in items:
|
|
60
|
+
if k in dct:
|
|
61
|
+
raise KeyError(k)
|
|
62
|
+
dct[k] = v
|
|
63
|
+
return dct
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def all_equal(it: ta.Iterable[T]) -> bool:
|
|
67
|
+
i = iter(it)
|
|
68
|
+
try:
|
|
69
|
+
l = next(i)
|
|
70
|
+
except StopIteration:
|
|
71
|
+
return True
|
|
72
|
+
return all(r == l for r in i)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def all_not_equal(it: ta.Iterable[T]) -> bool:
|
|
76
|
+
s = set()
|
|
77
|
+
for v in it:
|
|
78
|
+
if v in s:
|
|
79
|
+
return False
|
|
80
|
+
s.add(v)
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def key_cmp(fn: ta.Callable[[K, K], int]) -> ta.Callable[[tuple[K, V], tuple[K, V]], int]:
|
|
85
|
+
return lambda t0, t1: fn(t0[0], t1[0])
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def indexes(it: ta.Iterable[T]) -> dict[T, int]:
|
|
89
|
+
return {e: i for i, e in enumerate(it)}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def mut_unify_sets(sets: ta.Iterable[set[T]]) -> list[set[T]]:
|
|
93
|
+
rem: list[set[T]] = list(sets)
|
|
94
|
+
ret: list[set[T]] = []
|
|
95
|
+
while rem:
|
|
96
|
+
cur = rem.pop()
|
|
97
|
+
while True:
|
|
98
|
+
moved = False
|
|
99
|
+
for i in range(len(rem) - 1, -1, -1):
|
|
100
|
+
if any(e in cur for e in rem[i]):
|
|
101
|
+
cur.update(rem.pop(i))
|
|
102
|
+
moved = True
|
|
103
|
+
if not moved:
|
|
104
|
+
break
|
|
105
|
+
ret.append(cur)
|
|
106
|
+
if ret:
|
|
107
|
+
all_ = set(itertools.chain.from_iterable(ret))
|
|
108
|
+
num = sum(map(len, ret))
|
|
109
|
+
check.equal(len(all_), num)
|
|
110
|
+
return ret
|
|
File without changes
|