pythonic-fp.splitends 2.0.2__py3-none-any.whl → 3.1.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.
- pythonic_fp/splitends/__init__.py +17 -14
- pythonic_fp/splitends/splitend.py +144 -52
- pythonic_fp/splitends/splitend_node.py +62 -27
- {pythonic_fp_splitends-2.0.2.dist-info → pythonic_fp_splitends-3.1.0.dist-info}/METADATA +27 -34
- pythonic_fp_splitends-3.1.0.dist-info/RECORD +8 -0
- pythonic_fp/splitends/__init__.pyi +0 -0
- pythonic_fp/splitends/splitend.pyi +0 -31
- pythonic_fp/splitends/splitend_node.pyi +0 -20
- pythonic_fp_splitends-2.0.2.dist-info/RECORD +0 -11
- {pythonic_fp_splitends-2.0.2.dist-info → pythonic_fp_splitends-3.1.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_splitends-2.0.2.dist-info → pythonic_fp_splitends-3.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,24 +12,27 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
"""
|
|
15
|
+
"""
|
|
16
|
+
.. admonition:: Mutable stack objects that can safely share data
|
|
17
|
+
|
|
18
|
+
Python package implementing a singularly linked stack of nodes called a ``SplitEnd``.
|
|
19
|
+
While mutable, these data structures can safely share immutable data nodes between
|
|
20
|
+
themselves. These nodes, of type ``SENode``, always contain data. A root node is
|
|
21
|
+
a node whose previous node is itself. Root nodes mark the bottom of the stack.
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
a node whose previous node is itself. Root nodes mark the bottom of the stack.
|
|
23
|
+
Like one of many "split ends" from shafts of hair, a ``SplitEnd`` can be "snipped"
|
|
24
|
+
shorter or "extended" further from its "end" node at the top of the stack. Its "root"
|
|
25
|
+
node is at the bottom of the stack and can not be "snipped" or "cut" off.
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
node is at the bottom of the stack and can not be "snipped" or "cut" off.
|
|
27
|
+
A ``SplitEnd`` can be duplicated onto a compatible root node. By compatible, the
|
|
28
|
+
new root must contain data that compares as equal to the old root node.
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
new root must contain data that compares as equal to the old root node.
|
|
30
|
+
.. admonition:: Future directions
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
be hashable. The ``scalp.add(d)`` method will return the unique root node with data
|
|
31
|
-
that compares as equal to ``d``, or create a new root node if such a contained node
|
|
32
|
-
does not exist.
|
|
32
|
+
A ``scalp`` is a container of root nodes all of whose contained data must
|
|
33
|
+
be hashable. The ``scalp.add(d)`` method will return the unique root node with data
|
|
34
|
+
that compares as equal to ``d``, or create a new root node if such a contained node
|
|
35
|
+
does not exist.
|
|
33
36
|
|
|
34
37
|
"""
|
|
35
38
|
|
|
@@ -19,16 +19,20 @@ Class SplitEnds
|
|
|
19
19
|
.. admonition:: LIFO stacks safely sharing immutable data.
|
|
20
20
|
|
|
21
21
|
- each ``SplitEnd`` is a very simple stateful (mutable) LIFO stack
|
|
22
|
-
- data can be either "extended" to or "snipped" off the "end"
|
|
23
|
-
-
|
|
22
|
+
- data can be either "extended" to or "snipped" off the "end"
|
|
23
|
+
- "root" of a ``SplitEnd`` is embedded in a ``scalp``
|
|
24
24
|
|
|
25
|
-
-
|
|
25
|
+
- the root data is immutable
|
|
26
|
+
- it cannot be split off
|
|
26
27
|
|
|
27
28
|
- different mutable split ends can safely share the same "tail"
|
|
28
29
|
- each ``SplitEnd`` sees itself as a singularly linked list
|
|
29
30
|
- bush-like datastructures can be formed using multiple ``SplitEnds``
|
|
30
31
|
- the ``SplitEnd.split`` and ``len`` methods are O(1)
|
|
31
|
-
- in boolean context
|
|
32
|
+
- in a boolean context
|
|
33
|
+
|
|
34
|
+
- falsy just a "root"
|
|
35
|
+
- truthy otherwise
|
|
32
36
|
|
|
33
37
|
"""
|
|
34
38
|
|
|
@@ -52,8 +56,10 @@ class SplitEnd[D]:
|
|
|
52
56
|
|
|
53
57
|
def __init__(self, *ds: D, root: SENode[D] | _Sentinel = _sentinel) -> None:
|
|
54
58
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
.. admonition:: init
|
|
60
|
+
|
|
61
|
+
:param root_data: Irremovable initial data at bottom of stack.
|
|
62
|
+
:param ds: Removable data to be pushed onto splitend stack.
|
|
57
63
|
|
|
58
64
|
"""
|
|
59
65
|
if root is _sentinel:
|
|
@@ -78,28 +84,57 @@ class SplitEnd[D]:
|
|
|
78
84
|
self._end, self._root, self._count = end, root_node, count
|
|
79
85
|
|
|
80
86
|
def __iter__(self) -> Iterator[D]:
|
|
87
|
+
"""
|
|
88
|
+
.. admonition:: iter
|
|
89
|
+
|
|
90
|
+
Iterate from end to root.
|
|
91
|
+
|
|
92
|
+
:yields: data from end to root
|
|
93
|
+
|
|
94
|
+
"""
|
|
81
95
|
return iter(self._end)
|
|
82
96
|
|
|
83
97
|
def __reversed__(self) -> Iterator[D]:
|
|
98
|
+
"""
|
|
99
|
+
.. admonition:: reverse iter
|
|
100
|
+
|
|
101
|
+
Iterate from end to root.
|
|
102
|
+
|
|
103
|
+
:yields: data from end to root
|
|
104
|
+
|
|
105
|
+
"""
|
|
84
106
|
return reversed(list(self))
|
|
85
107
|
|
|
86
108
|
def __bool__(self) -> bool:
|
|
87
109
|
"""
|
|
88
|
-
|
|
110
|
+
.. admonition:: bool
|
|
111
|
+
|
|
112
|
+
:returns: ``True`` if ``SplitEnd`` is not just its root node.
|
|
89
113
|
|
|
90
114
|
"""
|
|
91
115
|
return bool(self._end)
|
|
92
116
|
|
|
93
117
|
def __len__(self) -> int:
|
|
94
|
-
|
|
118
|
+
"""
|
|
119
|
+
.. admonition:: len
|
|
95
120
|
|
|
96
|
-
|
|
97
|
-
return 'SplitEend(' + ', '.join(map(repr, reversed(self))) + ')'
|
|
121
|
+
:returns: The number of nodes on the ``Splitend``.
|
|
98
122
|
|
|
99
|
-
|
|
100
|
-
return
|
|
123
|
+
"""
|
|
124
|
+
return self._count
|
|
101
125
|
|
|
102
126
|
def __eq__(self, other: object, /) -> bool:
|
|
127
|
+
"""
|
|
128
|
+
.. admonition:: equality comparison
|
|
129
|
+
|
|
130
|
+
Efficiently compare two ``SplitEnds``.
|
|
131
|
+
|
|
132
|
+
:returns: ``True`` only if ``other`` is also a ``Splitend``
|
|
133
|
+
whose corresponding data to ``self`` compares as
|
|
134
|
+
equal and both share the same root node.
|
|
135
|
+
Otherwise ``False``.
|
|
136
|
+
|
|
137
|
+
"""
|
|
103
138
|
if not isinstance(other, type(self)):
|
|
104
139
|
return False
|
|
105
140
|
|
|
@@ -120,11 +155,54 @@ class SplitEnd[D]:
|
|
|
120
155
|
right = right.prev()
|
|
121
156
|
return True
|
|
122
157
|
|
|
158
|
+
def __repr__(self) -> str:
|
|
159
|
+
"""
|
|
160
|
+
.. admonition:: repr string
|
|
161
|
+
|
|
162
|
+
Construct string to reproduce the ``SplitEnd``.
|
|
163
|
+
TODO: Fix, does not include root node.
|
|
164
|
+
|
|
165
|
+
:returns: String to reproduce the ``SplitEnd``.
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
return 'SplitEend(' + ', '.join(map(repr, reversed(self))) + ')'
|
|
169
|
+
|
|
170
|
+
def __str__(self) -> str:
|
|
171
|
+
"""
|
|
172
|
+
.. admonition:: user string
|
|
173
|
+
|
|
174
|
+
Construct string meaningful to an end user.
|
|
175
|
+
Does not give root node info.
|
|
176
|
+
|
|
177
|
+
:returns: String to reproduce the ``SplitEnd``.
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
return '>< ' + ' -> '.join(map(str, self)) + ' ||'
|
|
181
|
+
|
|
182
|
+
def snip(self) -> D:
|
|
183
|
+
"""
|
|
184
|
+
.. admonition:: cut just tip
|
|
185
|
+
|
|
186
|
+
:returns: Data from snipped tip,
|
|
187
|
+
just return root data if at root.
|
|
188
|
+
|
|
189
|
+
"""
|
|
190
|
+
if self._count > 1:
|
|
191
|
+
data, self._end, self._count = self._end.both() + (self._count - 1,)
|
|
192
|
+
else:
|
|
193
|
+
data = self._end.data()
|
|
194
|
+
|
|
195
|
+
return data
|
|
196
|
+
|
|
123
197
|
def cut(self, num: int | None = None) -> tuple[D, ...]:
|
|
124
|
-
"""
|
|
198
|
+
"""
|
|
199
|
+
.. admonition:: Cut data off end of SplitEnd
|
|
200
|
+
|
|
201
|
+
Pop "cut" data off Split, just copy root data.
|
|
125
202
|
|
|
126
|
-
|
|
127
|
-
|
|
203
|
+
:param num: Optional number of nodes to cut,
|
|
204
|
+
default is entire stack.
|
|
205
|
+
:returns: Tuple of data cut off from end towards root.
|
|
128
206
|
|
|
129
207
|
"""
|
|
130
208
|
if num is None or num > self._count:
|
|
@@ -147,10 +225,13 @@ class SplitEnd[D]:
|
|
|
147
225
|
return data
|
|
148
226
|
|
|
149
227
|
def extend(self, *ds: D) -> None:
|
|
150
|
-
"""
|
|
151
|
-
|
|
228
|
+
"""
|
|
229
|
+
.. admonition:: extend SplitEnd with data
|
|
152
230
|
|
|
153
|
-
|
|
231
|
+
Add data onto the tip of the SplitEnd. Like adding
|
|
232
|
+
a hair extension.
|
|
233
|
+
|
|
234
|
+
:param ds: data to extend the splitend
|
|
154
235
|
|
|
155
236
|
"""
|
|
156
237
|
for d in ds:
|
|
@@ -158,37 +239,48 @@ class SplitEnd[D]:
|
|
|
158
239
|
self._end, self._count = node, self._count + 1
|
|
159
240
|
|
|
160
241
|
def peak(self) -> D:
|
|
161
|
-
"""
|
|
242
|
+
"""
|
|
243
|
+
.. admonition:: peak at end
|
|
162
244
|
|
|
163
|
-
|
|
245
|
+
Return the data at end (top) of the SplitEnd
|
|
246
|
+
without consuming it.
|
|
247
|
+
|
|
248
|
+
:returns: The data at the end (tip) of the SplitEnd.
|
|
164
249
|
|
|
165
250
|
"""
|
|
166
251
|
return self._end.data()
|
|
167
252
|
|
|
168
253
|
def root(self) -> SENode[D]:
|
|
169
254
|
"""
|
|
170
|
-
|
|
255
|
+
.. admonition:: get root
|
|
256
|
+
|
|
257
|
+
:returns: The root SENode node of the SplitEnd.
|
|
171
258
|
|
|
172
259
|
"""
|
|
173
260
|
return self._root
|
|
174
261
|
|
|
175
262
|
def reroot(self, root: SENode[D]) -> 'SplitEnd[D]':
|
|
176
|
-
"""
|
|
263
|
+
"""
|
|
264
|
+
.. admonition:: re-root SplitEnd
|
|
177
265
|
|
|
178
|
-
|
|
266
|
+
Create a brand new SplitEnd with the same data but different root.
|
|
179
267
|
|
|
180
|
-
|
|
268
|
+
:returns: New SplitEnd with the same data
|
|
269
|
+
and the new ``root``.
|
|
270
|
+
:raises ValueError: If new and original root nodes
|
|
271
|
+
are not compatible.
|
|
181
272
|
|
|
182
|
-
|
|
273
|
+
.. note::
|
|
183
274
|
|
|
184
|
-
|
|
275
|
+
Two nodes are compatible root nodes if and only if
|
|
185
276
|
|
|
186
|
-
|
|
277
|
+
- they are both actually root nodes
|
|
187
278
|
|
|
188
|
-
|
|
279
|
+
- which implies that their previous nodes are themselves
|
|
189
280
|
|
|
190
|
-
|
|
191
|
-
|
|
281
|
+
- their data compare as equal
|
|
282
|
+
|
|
283
|
+
- comparing by identity is too strong
|
|
192
284
|
|
|
193
285
|
"""
|
|
194
286
|
if not root:
|
|
@@ -205,23 +297,14 @@ class SplitEnd[D]:
|
|
|
205
297
|
|
|
206
298
|
return SplitEnd(*lifo, root = root)
|
|
207
299
|
|
|
208
|
-
def
|
|
209
|
-
"""Snip data off tip of SplitEnd. Just return data if tip is root.
|
|
210
|
-
|
|
211
|
-
:returns: Data snipped off tip, just return root data if at root.
|
|
212
|
-
|
|
300
|
+
def split(self, *ds: D) -> 'SplitEnd[D]':
|
|
213
301
|
"""
|
|
214
|
-
|
|
215
|
-
data, self._end, self._count = self._end.both() + (self._count - 1,)
|
|
216
|
-
else:
|
|
217
|
-
data = self._end.data()
|
|
302
|
+
.. admonition:: split
|
|
218
303
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def split(self, *ds: D) -> 'SplitEnd[D]':
|
|
222
|
-
"""Split the end and add more data.
|
|
304
|
+
Split the end and add more data.
|
|
223
305
|
|
|
224
|
-
|
|
306
|
+
:returns: New instance, same data nodes plus
|
|
307
|
+
additional ones on end. Same root node.
|
|
225
308
|
|
|
226
309
|
"""
|
|
227
310
|
se: SplitEnd[D] = SplitEnd(self._root.data())
|
|
@@ -235,11 +318,16 @@ class SplitEnd[D]:
|
|
|
235
318
|
def fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
236
319
|
|
|
237
320
|
def fold[T](self, f: Callable[[T, D], T], init: T | None = None) -> T:
|
|
238
|
-
"""
|
|
321
|
+
"""
|
|
322
|
+
.. admonition:: fold
|
|
323
|
+
|
|
324
|
+
Reduce with a function, folding from tip to root.
|
|
239
325
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
326
|
+
:param f: Folding function, first argument
|
|
327
|
+
is for the accumulator.
|
|
328
|
+
:param init: Optional initial starting value for the fold.
|
|
329
|
+
:returns: Reduced value folding from tip to root
|
|
330
|
+
in natural LIFO order.
|
|
243
331
|
|
|
244
332
|
"""
|
|
245
333
|
if init is None:
|
|
@@ -252,11 +340,15 @@ class SplitEnd[D]:
|
|
|
252
340
|
def rev_fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
253
341
|
|
|
254
342
|
def rev_fold[T](self, f: Callable[[T, D], T], init: T | None = None) -> T:
|
|
255
|
-
"""
|
|
343
|
+
"""
|
|
344
|
+
.. admonition:: reverse fold
|
|
345
|
+
|
|
346
|
+
Reduce with a function, fold from root to tip.
|
|
256
347
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
348
|
+
:param f: Folding function, first argument
|
|
349
|
+
is for the accumulator.
|
|
350
|
+
:param init: Optional initial starting value for the fold.
|
|
351
|
+
:returns: Reduced value folding from root to tip.
|
|
260
352
|
|
|
261
353
|
"""
|
|
262
354
|
if init is None:
|
|
@@ -13,10 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
------------
|
|
16
|
+
.. admonition:: SplitEnd node
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
Used to make inwardly directed bush-like graphs.
|
|
20
19
|
|
|
21
20
|
- designed so multiple splitends can safely share the same data
|
|
22
21
|
- nodes always contain data
|
|
@@ -51,8 +50,12 @@ class SENode[D]:
|
|
|
51
50
|
|
|
52
51
|
def __init__(self, data: D, prev: Self | _Sentinel = _sentinel) -> None:
|
|
53
52
|
"""
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
.. admonition:: init
|
|
54
|
+
|
|
55
|
+
:param data: Nodes always contain data of type ``D``.
|
|
56
|
+
:param prev: Link to previous node, points to ``self``
|
|
57
|
+
if a root node.
|
|
58
|
+
|
|
56
59
|
"""
|
|
57
60
|
self._data = data
|
|
58
61
|
if prev is not _sentinel:
|
|
@@ -62,11 +65,20 @@ class SENode[D]:
|
|
|
62
65
|
|
|
63
66
|
def __bool__(self) -> bool:
|
|
64
67
|
"""
|
|
65
|
-
|
|
68
|
+
.. admonition:: bool
|
|
69
|
+
|
|
70
|
+
:returns: ``True`` only if ``SENode`` is not a root node.
|
|
71
|
+
|
|
66
72
|
"""
|
|
67
73
|
return self._prev is not self
|
|
68
74
|
|
|
69
75
|
def __iter__(self) -> Iterator[D]:
|
|
76
|
+
"""
|
|
77
|
+
.. admonition:: iter
|
|
78
|
+
|
|
79
|
+
:yields: Node date until and including root node.
|
|
80
|
+
|
|
81
|
+
"""
|
|
70
82
|
node = self
|
|
71
83
|
while node:
|
|
72
84
|
yield node._data
|
|
@@ -75,8 +87,18 @@ class SENode[D]:
|
|
|
75
87
|
|
|
76
88
|
def __eq__(self, other: object) -> bool:
|
|
77
89
|
"""
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
.. admonition:: equality comparison
|
|
91
|
+
|
|
92
|
+
Two ``SENodes`` nodes are equal if their previous nodes
|
|
93
|
+
are the same object and their data compare as equal.
|
|
94
|
+
|
|
95
|
+
:param other:
|
|
96
|
+
:returns: ``True`` if ``other`` is a SplitEnd which compares
|
|
97
|
+
as equal to ``self`` as described above.
|
|
98
|
+
|
|
99
|
+
.. note::
|
|
100
|
+
|
|
101
|
+
Will be useful when consolidating SplitEnds.
|
|
80
102
|
|
|
81
103
|
"""
|
|
82
104
|
if not isinstance(other, type(self)):
|
|
@@ -88,35 +110,43 @@ class SENode[D]:
|
|
|
88
110
|
return True
|
|
89
111
|
return False
|
|
90
112
|
|
|
91
|
-
def both(self) -> tuple[D, Self]:
|
|
92
|
-
"""Peak at data and previous node, if a root then data and self.
|
|
93
|
-
|
|
94
|
-
:returns: tuple of type tuple[D, SENode[D]]
|
|
95
|
-
|
|
96
|
-
"""
|
|
97
|
-
return self._data, self._prev
|
|
98
|
-
|
|
99
113
|
def data(self) -> D:
|
|
100
|
-
"""
|
|
114
|
+
"""
|
|
115
|
+
.. admonition:: peak at data in SENode
|
|
101
116
|
|
|
102
|
-
|
|
117
|
+
:returns: The data stored in the ``SENode``.
|
|
103
118
|
|
|
104
119
|
"""
|
|
105
120
|
return self._data
|
|
106
121
|
|
|
107
122
|
def prev(self) -> Self:
|
|
108
|
-
"""
|
|
123
|
+
"""
|
|
124
|
+
.. admonition:: peak at previous node
|
|
109
125
|
|
|
110
|
-
|
|
126
|
+
:returns: The previous node stored in the ``SENode``.
|
|
111
127
|
|
|
112
128
|
"""
|
|
113
129
|
return self._prev
|
|
114
130
|
|
|
131
|
+
def both(self) -> tuple[D, Self]:
|
|
132
|
+
"""
|
|
133
|
+
.. admonition:: both data and previous node
|
|
134
|
+
|
|
135
|
+
Peak at data and previous node,
|
|
136
|
+
if a root then data and ``self``.
|
|
137
|
+
|
|
138
|
+
:returns: Tuple of type ``tuple[D, SENode[D]]``
|
|
139
|
+
|
|
140
|
+
"""
|
|
141
|
+
return self._data, self._prev
|
|
142
|
+
|
|
115
143
|
def push(self, data: D) -> Self:
|
|
116
|
-
"""
|
|
144
|
+
"""
|
|
145
|
+
.. admonition:: push date to create new ``SENode[D]``
|
|
117
146
|
|
|
118
|
-
|
|
119
|
-
|
|
147
|
+
:param data: Data for new node to contain.
|
|
148
|
+
:returns: New ``SENode`` whose previous node is
|
|
149
|
+
the current node.
|
|
120
150
|
|
|
121
151
|
"""
|
|
122
152
|
return cast(Self, SENode(data, self))
|
|
@@ -127,11 +157,16 @@ class SENode[D]:
|
|
|
127
157
|
def fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
128
158
|
|
|
129
159
|
def fold[T](self, f: Callable[[T, D], T], init: T | _Sentinel = _sentinel) -> T:
|
|
130
|
-
"""
|
|
160
|
+
"""
|
|
161
|
+
.. admonition:: fold
|
|
162
|
+
|
|
163
|
+
Fold data across linked nodes with a function.
|
|
131
164
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
165
|
+
:param f: Folding function, first argument
|
|
166
|
+
is for accumulated value.`
|
|
167
|
+
:param init: Optional initial starting value for the fold.
|
|
168
|
+
:returns: Reduced value folded from end to root
|
|
169
|
+
in natural LIFO order.
|
|
135
170
|
|
|
136
171
|
"""
|
|
137
172
|
if init is not _sentinel:
|
|
@@ -1,38 +1,44 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-splitends
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Mutable stack
|
|
3
|
+
Version: 3.1.0
|
|
4
|
+
Summary: Mutable stack datastructures that can safely share data.
|
|
5
5
|
Keywords: SplitEnd,lifo,stack
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
|
-
Requires-Python: >=3.
|
|
8
|
-
Description-Content-Type: text/
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
9
|
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: Framework :: Pytest
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
16
|
Classifier: Typing :: Typed
|
|
16
17
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: pythonic-fp-fptools>=
|
|
18
|
-
Requires-Dist: pythonic-fp-iterables>=5.1.
|
|
19
|
-
Requires-Dist: pythonic-fp-queues>=5.1.
|
|
20
|
-
|
|
21
|
-
Project-URL:
|
|
22
|
-
Project-URL:
|
|
23
|
-
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/homepage/build/html/
|
|
18
|
+
Requires-Dist: pythonic-fp-fptools>=6.1,<6.2
|
|
19
|
+
Requires-Dist: pythonic-fp-iterables>=5.1.4,<6
|
|
20
|
+
Requires-Dist: pythonic-fp-queues>=5.1.3,<6
|
|
21
|
+
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-splitends/blob/main/CHANGELOG.md
|
|
22
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp-splitends/release/html/
|
|
23
|
+
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
24
24
|
Project-URL: Source, https://github.com/grscheller/pythonic-fp-splitends
|
|
25
|
-
Provides-Extra: test
|
|
26
25
|
|
|
27
|
-
Pythonic FP - SplitEnds
|
|
28
|
-
|
|
26
|
+
# Pythonic FP - SplitEnds
|
|
27
|
+
|
|
28
|
+
Package Implementing a singularly linked LIFO queue called
|
|
29
|
+
a `SplitEnd`. These data structures can safely share data nodes
|
|
30
|
+
between themselves.
|
|
29
31
|
|
|
30
32
|
PyPI project
|
|
31
|
-
|
|
33
|
+
[pythonic-fp.splitends](https://pypi.org/project/pythonic-fp-splitends/).
|
|
34
|
+
Part of the
|
|
35
|
+
[pythonic-fp](https://grscheller.github.io/pythonic-fp/)
|
|
36
|
+
PyPI projects.
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
## Documentation
|
|
39
|
+
|
|
40
|
+
Documentation and other links for this project are hosted on
|
|
41
|
+
[GitHub Pages](https://grscheller.github.io/pythonic-fp/projects/splitends.html).
|
|
36
42
|
|
|
37
43
|
- each ``SplitEnd`` is a very simple stateful (mutable) LIFO stack
|
|
38
44
|
- data can be "extended" to or "snipped" off of the end (tip)
|
|
@@ -43,21 +49,8 @@ between themselves.
|
|
|
43
49
|
- the ``SplitEnd`` copy method and ``len`` are O(1)
|
|
44
50
|
- in boolean context returns true if the ``SplitEnd`` is not just a "root"
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
`pythonic-fp
|
|
48
|
-
<https://grscheller.github.io/pythonic-fp>`_
|
|
49
|
-
PyPI projects.
|
|
50
|
-
|
|
51
|
-
Documentation
|
|
52
|
-
-------------
|
|
53
|
-
|
|
54
|
-
Documentation for this project is hosted on
|
|
55
|
-
`GitHub Pages
|
|
56
|
-
<https://grscheller.github.io/pythonic-fp/splitends>`_.
|
|
57
|
-
|
|
58
|
-
Copyright and License
|
|
59
|
-
---------------------
|
|
52
|
+
## Copyright and License
|
|
60
53
|
|
|
61
|
-
Copyright (c) 2023-
|
|
54
|
+
Copyright (c) 2023-2026 Geoffrey R. Scheller. Licensed under the Apache
|
|
62
55
|
License, Version 2.0. See the LICENSE file for details.
|
|
63
56
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pythonic_fp/splitends/__init__.py,sha256=4em0AExIcd7slGzjUD5iUDiYVSHyrgQdqce0UosgBno,1893
|
|
2
|
+
pythonic_fp/splitends/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
pythonic_fp/splitends/splitend.py,sha256=RFBsJcEh-NGRAtOizbYShNznseutIRoeOJbCeEJBxCM,10334
|
|
4
|
+
pythonic_fp/splitends/splitend_node.py,sha256=E8MIZEDg6ZRY_0JfQnZyTD2Xek2JAg_epEu8sCzLadY,5139
|
|
5
|
+
pythonic_fp_splitends-3.1.0.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
6
|
+
pythonic_fp_splitends-3.1.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
7
|
+
pythonic_fp_splitends-3.1.0.dist-info/METADATA,sha256=uPJtwQGq9okGujWDOX1HBei7AQgB4ZhiDwk0bJaN8GA,2316
|
|
8
|
+
pythonic_fp_splitends-3.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from .splitend_node import SENode
|
|
2
|
-
from collections.abc import Callable, Iterator
|
|
3
|
-
from pythonic_fp.gadgets.sentinels.flavored import Sentinel
|
|
4
|
-
from typing import overload
|
|
5
|
-
|
|
6
|
-
__all__ = ['SplitEnd']
|
|
7
|
-
|
|
8
|
-
type _SecretType = tuple[str, str, str]
|
|
9
|
-
type _Sentinel = Sentinel[_SecretType]
|
|
10
|
-
class SplitEnd[D]:
|
|
11
|
-
def __init__(self, *ds: D, root: SENode[D] | _Sentinel = ...) -> None: ...
|
|
12
|
-
def __iter__(self) -> Iterator[D]: ...
|
|
13
|
-
def __reversed__(self) -> Iterator[D]: ...
|
|
14
|
-
def __bool__(self) -> bool: ...
|
|
15
|
-
def __len__(self) -> int: ...
|
|
16
|
-
def __eq__(self, other: object) -> bool: ...
|
|
17
|
-
def cut(self, num: int | None = None) -> tuple[D, ...]: ...
|
|
18
|
-
def extend(self, *ds: D) -> None: ...
|
|
19
|
-
def peak(self) -> D: ...
|
|
20
|
-
def root(self) -> SENode[D]: ...
|
|
21
|
-
def reroot(self, root: SENode[D]) -> SplitEnd[D]: ...
|
|
22
|
-
def snip(self) -> D: ...
|
|
23
|
-
def split(self, *ds: D) -> SplitEnd[D]: ...
|
|
24
|
-
@overload
|
|
25
|
-
def fold[T](self, f: Callable[[D, D], D]) -> D: ...
|
|
26
|
-
@overload
|
|
27
|
-
def fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
28
|
-
@overload
|
|
29
|
-
def rev_fold[T](self, f: Callable[[D, D], D]) -> D: ...
|
|
30
|
-
@overload
|
|
31
|
-
def rev_fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
from collections.abc import Callable, Iterator
|
|
2
|
-
from pythonic_fp.gadgets.sentinels.flavored import Sentinel
|
|
3
|
-
from typing import Self, overload
|
|
4
|
-
|
|
5
|
-
__all__ = ['SENode']
|
|
6
|
-
|
|
7
|
-
type _Sentinel = Sentinel[str]
|
|
8
|
-
class SENode[D]:
|
|
9
|
-
def __init__(self, data: D, prev: Self | _Sentinel = ...) -> None: ...
|
|
10
|
-
def __bool__(self) -> bool: ...
|
|
11
|
-
def __iter__(self) -> Iterator[D]: ...
|
|
12
|
-
def __eq__(self, other: object) -> bool: ...
|
|
13
|
-
def both(self) -> tuple[D, Self]: ...
|
|
14
|
-
def data(self) -> D: ...
|
|
15
|
-
def prev(self) -> Self: ...
|
|
16
|
-
def push(self, data: D) -> Self: ...
|
|
17
|
-
@overload
|
|
18
|
-
def fold(self, f: Callable[[D, D], D]) -> D: ...
|
|
19
|
-
@overload
|
|
20
|
-
def fold[T](self, f: Callable[[T, D], T], init: T) -> T: ...
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
pythonic_fp/splitends/__init__.py,sha256=T3FgFehJkrlKx2OKHJJETDcEJ_2nKfyl96wTb4Nw6Fw,1780
|
|
2
|
-
pythonic_fp/splitends/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
pythonic_fp/splitends/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
pythonic_fp/splitends/splitend.py,sha256=TkLQ5o4-SCnnC_HTpda6cSotaxyQ6aNbc8DB81qNqSI,8317
|
|
5
|
-
pythonic_fp/splitends/splitend.pyi,sha256=OdTRATFXX5smbpwc8wm3gt4yyeTd_kN8VbMeNYl2Cho,1193
|
|
6
|
-
pythonic_fp/splitends/splitend_node.py,sha256=0Qz_oIvwbvtlYZOD-tZ0lD4PxMRysFPkBNPTBkGdkQk,4306
|
|
7
|
-
pythonic_fp/splitends/splitend_node.pyi,sha256=TozeGg4lmjMf0UPfZRTxRJR2kRpq0053VjbjIBUeosk,705
|
|
8
|
-
pythonic_fp_splitends-2.0.2.dist-info/licenses/LICENSE,sha256=IJMkVWQUVy-SonK6SMaMotDQ6Zb-lVi2bUTiGp1GUO8,10774
|
|
9
|
-
pythonic_fp_splitends-2.0.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
10
|
-
pythonic_fp_splitends-2.0.2.dist-info/METADATA,sha256=l9gYIuYaAd9pIQwLAe_6AHnSjowRzx6JKsV4uxtI6dQ,2381
|
|
11
|
-
pythonic_fp_splitends-2.0.2.dist-info/RECORD,,
|
|
File without changes
|
{pythonic_fp_splitends-2.0.2.dist-info → pythonic_fp_splitends-3.1.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|