pythonstl 1.1.4__tar.gz → 1.1.5__tar.gz

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.
Files changed (57) hide show
  1. {pythonstl-1.1.4 → pythonstl-1.1.5}/PKG-INFO +3 -3
  2. {pythonstl-1.1.4 → pythonstl-1.1.5}/README.md +1 -1
  3. {pythonstl-1.1.4 → pythonstl-1.1.5}/pyproject.toml +2 -2
  4. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/__init__.py +1 -1
  5. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/algorithms.py +330 -331
  6. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/map.py +1 -2
  7. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/priority_queue.py +1 -2
  8. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/queue.py +1 -2
  9. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/set.py +3 -4
  10. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/stack.py +1 -2
  11. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/vector.py +2 -3
  12. {pythonstl-1.1.4 → pythonstl-1.1.5}/.flake8 +0 -0
  13. {pythonstl-1.1.4 → pythonstl-1.1.5}/.github/FUNDING.yml +0 -0
  14. {pythonstl-1.1.4 → pythonstl-1.1.5}/.github/workflows/python.yml +0 -0
  15. {pythonstl-1.1.4 → pythonstl-1.1.5}/.gitignore +0 -0
  16. {pythonstl-1.1.4 → pythonstl-1.1.5}/Cargo.lock +0 -0
  17. {pythonstl-1.1.4 → pythonstl-1.1.5}/Cargo.toml +0 -0
  18. {pythonstl-1.1.4 → pythonstl-1.1.5}/LICENSE +0 -0
  19. {pythonstl-1.1.4 → pythonstl-1.1.5}/PUBLISHING.md +0 -0
  20. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/README.md +0 -0
  21. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_algorithms.py +0 -0
  22. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_all_structures.py +0 -0
  23. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_binary_search.py +0 -0
  24. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_map.py +0 -0
  25. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_native.cpp +0 -0
  26. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_rust_vs_py.py +0 -0
  27. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_stack.py +0 -0
  28. {pythonstl-1.1.4 → pythonstl-1.1.5}/benchmarks/benchmark_vector.py +0 -0
  29. {pythonstl-1.1.4 → pythonstl-1.1.5}/example_usage.py +0 -0
  30. {pythonstl-1.1.4 → pythonstl-1.1.5}/mypy.ini +0 -0
  31. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/_rust.pdb +0 -0
  32. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/core/__init__.py +0 -0
  33. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/core/base.py +0 -0
  34. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/core/exceptions.py +0 -0
  35. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/core/iterator.py +0 -0
  36. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/facade/__init__.py +0 -0
  37. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/__init__.py +0 -0
  38. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/associative/__init__.py +0 -0
  39. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/associative/_map_impl.py +0 -0
  40. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/associative/_set_impl.py +0 -0
  41. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/heaps/__init__.py +0 -0
  42. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/heaps/_priority_queue_impl.py +0 -0
  43. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/linear/__init__.py +0 -0
  44. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/linear/_queue_impl.py +0 -0
  45. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/linear/_stack_impl.py +0 -0
  46. {pythonstl-1.1.4 → pythonstl-1.1.5}/pythonstl/implementations/linear/_vector_impl.py +0 -0
  47. {pythonstl-1.1.4 → pythonstl-1.1.5}/setup.py +0 -0
  48. {pythonstl-1.1.4 → pythonstl-1.1.5}/src/lib.rs +0 -0
  49. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/__init__.py +0 -0
  50. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_algorithms.py +0 -0
  51. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_binary_search.py +0 -0
  52. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_map.py +0 -0
  53. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_priority_queue.py +0 -0
  54. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_queue.py +0 -0
  55. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_set.py +0 -0
  56. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_stack.py +0 -0
  57. {pythonstl-1.1.4 → pythonstl-1.1.5}/tests/test_vector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonstl
3
- Version: 1.1.4
3
+ Version: 1.1.5
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -15,7 +15,7 @@ Classifier: Operating System :: OS Independent
15
15
  License-File: LICENSE
16
16
  Summary: C++ STL-style containers implemented in Python using the Facade Design Pattern
17
17
  Keywords: stl,data-structures,containers,facade-pattern,cpp-stl,standard-template-library
18
- Author-email: PySTL Contributors <pythonstl@example.com>
18
+ Author-email: PySTL Contributors <anshsoni702@gmail.com>
19
19
  License: MIT
20
20
  Requires-Python: >=3.10
21
21
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
@@ -445,5 +445,5 @@ Contributions are welcome! Please:
445
445
  - GitHub: [@AnshMNSoni](https://github.com/AnshMNSoni)
446
446
  - Issues: [GitHub Issues](https://github.com/AnshMNSoni/PythonSTL/issues)
447
447
 
448
- **PythonSTL v0.1.1** - Bringing C++ STL elegance to Python
448
+ **PythonSTL v1.1.5** - Bringing C++ STL elegance to Python
449
449
 
@@ -419,4 +419,4 @@ Contributions are welcome! Please:
419
419
  - GitHub: [@AnshMNSoni](https://github.com/AnshMNSoni)
420
420
  - Issues: [GitHub Issues](https://github.com/AnshMNSoni/PythonSTL/issues)
421
421
 
422
- **PythonSTL v0.1.1** - Bringing C++ STL elegance to Python
422
+ **PythonSTL v1.1.5** - Bringing C++ STL elegance to Python
@@ -8,11 +8,11 @@ module-name = "pythonstl._rust"
8
8
 
9
9
  [project]
10
10
  name = "pythonstl"
11
- version = "1.1.4"
11
+ version = "1.1.5"
12
12
  description = "C++ STL-style containers implemented in Python using the Facade Design Pattern"
13
13
  readme = "README.md"
14
14
  authors = [
15
- {name = "PySTL Contributors", email = "pythonstl@example.com"}
15
+ {name = "PySTL Contributors", email = "anshsoni702@gmail.com"}
16
16
  ]
17
17
  license = {text = "MIT"}
18
18
  classifiers = [
@@ -8,7 +8,7 @@ This package provides clean, STL-compliant interfaces for common
8
8
  data structures while hiding implementation details from users.
9
9
  """
10
10
 
11
- __version__ = "1.1.4"
11
+ __version__ = "1.1.5"
12
12
  __author__ = "PySTL Contributors"
13
13
 
14
14
  from pythonstl.facade.stack import stack
@@ -1,331 +1,330 @@
1
- """
2
- C++ STL Algorithms Suite.
3
-
4
- This module provides replicas of standard C++ algorithms from <algorithm>
5
- with dynamic Rust backend loading and in-place list mutation.
6
- """
7
-
8
- from typing import Callable, Any
9
-
10
- try:
11
- from pythonstl._rust import next_permutation as _rust_next_permutation
12
- from pythonstl._rust import prev_permutation as _rust_prev_permutation
13
- from pythonstl._rust import nth_element as _rust_nth_element
14
- from pythonstl._rust import partition as _rust_partition
15
- from pythonstl._rust import lower_bound as _rust_lower_bound
16
- from pythonstl._rust import upper_bound as _rust_upper_bound
17
- from pythonstl._rust import binary_search as _rust_binary_search
18
- from pythonstl._rust import equal_range as _rust_equal_range
19
- RUST_AVAILABLE = True
20
- except ImportError:
21
- RUST_AVAILABLE = False
22
-
23
-
24
- # ----------------- Pure-Python Fallbacks -----------------
25
-
26
- def _py_next_permutation(arr: list) -> bool:
27
- n = len(arr)
28
- if n <= 1:
29
- return False
30
-
31
- i = n - 2
32
- while i >= 0 and arr[i] >= arr[i + 1]:
33
- i -= 1
34
-
35
- if i < 0:
36
- arr.reverse()
37
- return False
38
-
39
- j = n - 1
40
- while arr[j] <= arr[i]:
41
- j -= 1
42
-
43
- arr[i], arr[j] = arr[j], arr[i]
44
- arr[i + 1:] = reversed(arr[i + 1:])
45
- return True
46
-
47
-
48
- def _py_prev_permutation(arr: list) -> bool:
49
- n = len(arr)
50
- if n <= 1:
51
- return False
52
-
53
- i = n - 2
54
- while i >= 0 and arr[i] <= arr[i + 1]:
55
- i -= 1
56
-
57
- if i < 0:
58
- arr.reverse()
59
- return False
60
-
61
- j = n - 1
62
- while arr[j] >= arr[i]:
63
- j -= 1
64
-
65
- arr[i], arr[j] = arr[j], arr[i]
66
- arr[i + 1:] = reversed(arr[i + 1:])
67
- return True
68
-
69
-
70
- def _py_nth_element(arr: list, nth: int) -> None:
71
- n = len(arr)
72
- if nth < 0 or nth >= n:
73
- return
74
-
75
- left = 0
76
- right = n - 1
77
- while left < right:
78
- mid = left + (right - left) // 2
79
- arr[mid], arr[right] = arr[right], arr[mid]
80
- pivot = arr[right]
81
- i = left
82
- for j in range(left, right):
83
- if arr[j] < pivot:
84
- arr[i], arr[j] = arr[j], arr[i]
85
- i += 1
86
- arr[i], arr[right] = arr[right], arr[i]
87
-
88
- pivot_idx = i
89
- if pivot_idx == nth:
90
- return
91
- elif pivot_idx > nth:
92
- right = pivot_idx - 1
93
- else:
94
- left = pivot_idx + 1
95
-
96
-
97
-
98
- def _py_partition(arr: list, predicate: Callable[[Any], bool]) -> int:
99
- i = 0
100
- for j in range(len(arr)):
101
- if predicate(arr[j]):
102
- arr[i], arr[j] = arr[j], arr[i]
103
- i += 1
104
- return i
105
-
106
-
107
- def _py_lower_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> int:
108
- left = 0
109
- right = len(arr)
110
- while left < right:
111
- mid = left + (right - left) // 2
112
- mid_val = arr[mid]
113
- is_less = comp(mid_val, val) if comp else (mid_val < val)
114
- if is_less:
115
- left = mid + 1
116
- else:
117
- right = mid
118
- return left
119
-
120
-
121
- def _py_upper_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> int:
122
- left = 0
123
- right = len(arr)
124
- while left < right:
125
- mid = left + (right - left) // 2
126
- mid_val = arr[mid]
127
- is_less = comp(val, mid_val) if comp else (val < mid_val)
128
- if is_less:
129
- right = mid
130
- else:
131
- left = mid + 1
132
- return left
133
-
134
-
135
- def _py_binary_search(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> bool:
136
- if not arr:
137
- return False
138
- idx = _py_lower_bound(arr, val, comp)
139
- if idx < len(arr):
140
- elem = arr[idx]
141
- if comp:
142
- return not comp(elem, val) and not comp(val, elem)
143
- return elem == val
144
- return False
145
-
146
-
147
- def _py_equal_range(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> tuple[int, int]:
148
- return _py_lower_bound(arr, val, comp), _py_upper_bound(arr, val, comp)
149
-
150
-
151
- # ----------------- Public API Interfaces -----------------
152
-
153
- def next_permutation(arr: list, use_rust: bool = True) -> bool:
154
- """
155
- Rearranges elements in-place to the next lexicographically greater permutation.
156
-
157
- If the next permutation exists, rearranges elements and returns True.
158
- Otherwise, reverses the array to the smallest ascending order and returns False.
159
-
160
- Args:
161
- arr: The list to modify in-place.
162
- use_rust: Whether to use the compiled Rust backend (default: True).
163
-
164
- Returns:
165
- True if next permutation exists, False otherwise.
166
-
167
- Time Complexity:
168
- O(n) where n is len(arr)
169
- """
170
- if use_rust and RUST_AVAILABLE:
171
- return _rust_next_permutation(arr)
172
- return _py_next_permutation(arr)
173
-
174
-
175
- def prev_permutation(arr: list, use_rust: bool = True) -> bool:
176
- """
177
- Rearranges elements in-place to the next lexicographically smaller permutation.
178
-
179
- If the previous permutation exists, rearranges elements and returns True.
180
- Otherwise, reverses the array to the largest descending order and returns False.
181
-
182
- Args:
183
- arr: The list to modify in-place.
184
- use_rust: Whether to use the compiled Rust backend (default: True).
185
-
186
- Returns:
187
- True if prev permutation exists, False otherwise.
188
-
189
- Time Complexity:
190
- O(n) where n is len(arr)
191
- """
192
- if use_rust and RUST_AVAILABLE:
193
- return _rust_prev_permutation(arr)
194
- return _py_prev_permutation(arr)
195
-
196
-
197
- def nth_element(arr: list, nth: int, use_rust: bool = True) -> None:
198
- """
199
- Partitions the list in-place so that the element at index `nth` is the one
200
- that would be there if the list were completely sorted.
201
-
202
- All elements preceding `nth` are partitioned to be less than or equal to `nth`.
203
- All elements succeeding `nth` are partitioned to be greater than or equal to `nth`.
204
- Does not guarantee sorted order of the surrounding elements.
205
-
206
- Args:
207
- arr: The list to modify in-place.
208
- nth: The index that should contain the sorted element.
209
- use_rust: Whether to use the compiled Rust backend (default: True).
210
-
211
- Time Complexity:
212
- O(n) average case
213
- """
214
- if use_rust and RUST_AVAILABLE:
215
- _rust_nth_element(arr, nth)
216
- else:
217
- _py_nth_element(arr, nth)
218
-
219
-
220
- def partition(arr: list, predicate: Callable[[Any], bool], use_rust: bool = True) -> int:
221
- """
222
- Reorders the elements in the list in-place such that all elements for which
223
- `predicate` returns True precede all elements for which it returns False.
224
-
225
- Does not guarantee stable relative ordering.
226
-
227
- Args:
228
- arr: The list to modify in-place.
229
- predicate: A callable returning True or False for each element.
230
- use_rust: Whether to use the compiled Rust backend (default: True).
231
-
232
- Returns:
233
- The boundary index pointing to the first element that returned False.
234
-
235
- Time Complexity:
236
- O(n) where n is len(arr)
237
- """
238
- if use_rust and RUST_AVAILABLE:
239
- return _rust_partition(arr, predicate)
240
- return _py_partition(arr, predicate)
241
-
242
-
243
- def lower_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> int:
244
- """
245
- Returns the index of the first element in the range that does not compare less than `val`.
246
-
247
- Args:
248
- arr: The sorted list to search.
249
- val: The value to search for.
250
- comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
251
- use_rust: Whether to use the compiled Rust backend (default: True).
252
-
253
- Returns:
254
- The index of the first element that is >= val, or len(arr) if not found.
255
-
256
- Time Complexity:
257
- O(log n)
258
- """
259
- if use_rust and RUST_AVAILABLE:
260
- return _rust_lower_bound(arr, val, comp)
261
- return _py_lower_bound(arr, val, comp)
262
-
263
-
264
- def upper_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> int:
265
- """
266
- Returns the index of the first element in the range that compares greater than `val`.
267
-
268
- Args:
269
- arr: The sorted list to search.
270
- val: The value to search for.
271
- comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
272
- use_rust: Whether to use the compiled Rust backend (default: True).
273
-
274
- Returns:
275
- The index of the first element that is > val, or len(arr) if not found.
276
-
277
- Time Complexity:
278
- O(log n)
279
- """
280
- if use_rust and RUST_AVAILABLE:
281
- return _rust_upper_bound(arr, val, comp)
282
- return _py_upper_bound(arr, val, comp)
283
-
284
-
285
- def binary_search(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> bool:
286
- """
287
- Checks if a value is present in the sorted range.
288
-
289
- Args:
290
- arr: The sorted list to search.
291
- val: The value to search for.
292
- comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
293
- use_rust: Whether to use the compiled Rust backend (default: True).
294
-
295
- Returns:
296
- True if the element equivalent to val is found, False otherwise.
297
-
298
- Time Complexity:
299
- O(log n)
300
- """
301
- if use_rust and RUST_AVAILABLE:
302
- return _rust_binary_search(arr, val, comp)
303
- return _py_binary_search(arr, val, comp)
304
-
305
-
306
- def equal_range(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> tuple[int, int]:
307
- """
308
- Returns the range of elements equivalent to a given value.
309
-
310
- Args:
311
- arr: The sorted list to search.
312
- val: The value to search for.
313
- comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
314
- use_rust: Whether to use the compiled Rust backend (default: True).
315
-
316
- Returns:
317
- A tuple (lower_bound_index, upper_bound_index) defining the range of equivalent elements.
318
-
319
- Time Complexity:
320
- O(log n)
321
- """
322
- if use_rust and RUST_AVAILABLE:
323
- return _rust_equal_range(arr, val, comp)
324
- return _py_equal_range(arr, val, comp)
325
-
326
-
327
- __all__ = [
328
- 'next_permutation', 'prev_permutation', 'nth_element', 'partition',
329
- 'lower_bound', 'upper_bound', 'binary_search', 'equal_range',
330
- 'RUST_AVAILABLE'
331
- ]
1
+ """
2
+ C++ STL Algorithms Suite.
3
+
4
+ This module provides replicas of standard C++ algorithms from <algorithm>
5
+ with dynamic Rust backend loading and in-place list mutation.
6
+ """
7
+
8
+ from typing import Callable, Any
9
+
10
+ try:
11
+ from pythonstl._rust import next_permutation as _rust_next_permutation
12
+ from pythonstl._rust import prev_permutation as _rust_prev_permutation
13
+ from pythonstl._rust import nth_element as _rust_nth_element
14
+ from pythonstl._rust import partition as _rust_partition
15
+ from pythonstl._rust import lower_bound as _rust_lower_bound
16
+ from pythonstl._rust import upper_bound as _rust_upper_bound
17
+ from pythonstl._rust import binary_search as _rust_binary_search
18
+ from pythonstl._rust import equal_range as _rust_equal_range
19
+ RUST_AVAILABLE = True
20
+ except ImportError:
21
+ RUST_AVAILABLE = False
22
+
23
+
24
+ # ----------------- Pure-Python Fallbacks -----------------
25
+
26
+ def _py_next_permutation(arr: list) -> bool:
27
+ n = len(arr)
28
+ if n <= 1:
29
+ return False
30
+
31
+ i = n - 2
32
+ while i >= 0 and arr[i] >= arr[i + 1]:
33
+ i -= 1
34
+
35
+ if i < 0:
36
+ arr.reverse()
37
+ return False
38
+
39
+ j = n - 1
40
+ while arr[j] <= arr[i]:
41
+ j -= 1
42
+
43
+ arr[i], arr[j] = arr[j], arr[i]
44
+ arr[i + 1:] = reversed(arr[i + 1:])
45
+ return True
46
+
47
+
48
+ def _py_prev_permutation(arr: list) -> bool:
49
+ n = len(arr)
50
+ if n <= 1:
51
+ return False
52
+
53
+ i = n - 2
54
+ while i >= 0 and arr[i] <= arr[i + 1]:
55
+ i -= 1
56
+
57
+ if i < 0:
58
+ arr.reverse()
59
+ return False
60
+
61
+ j = n - 1
62
+ while arr[j] >= arr[i]:
63
+ j -= 1
64
+
65
+ arr[i], arr[j] = arr[j], arr[i]
66
+ arr[i + 1:] = reversed(arr[i + 1:])
67
+ return True
68
+
69
+
70
+ def _py_nth_element(arr: list, nth: int) -> None:
71
+ n = len(arr)
72
+ if nth < 0 or nth >= n:
73
+ return
74
+
75
+ left = 0
76
+ right = n - 1
77
+ while left < right:
78
+ mid = left + (right - left) // 2
79
+ arr[mid], arr[right] = arr[right], arr[mid]
80
+ pivot = arr[right]
81
+ i = left
82
+ for j in range(left, right):
83
+ if arr[j] < pivot:
84
+ arr[i], arr[j] = arr[j], arr[i]
85
+ i += 1
86
+ arr[i], arr[right] = arr[right], arr[i]
87
+
88
+ pivot_idx = i
89
+ if pivot_idx == nth:
90
+ return
91
+ elif pivot_idx > nth:
92
+ right = pivot_idx - 1
93
+ else:
94
+ left = pivot_idx + 1
95
+
96
+
97
+ def _py_partition(arr: list, predicate: Callable[[Any], bool]) -> int:
98
+ i = 0
99
+ for j in range(len(arr)):
100
+ if predicate(arr[j]):
101
+ arr[i], arr[j] = arr[j], arr[i]
102
+ i += 1
103
+ return i
104
+
105
+
106
+ def _py_lower_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> int:
107
+ left = 0
108
+ right = len(arr)
109
+ while left < right:
110
+ mid = left + (right - left) // 2
111
+ mid_val = arr[mid]
112
+ is_less = comp(mid_val, val) if comp else (mid_val < val)
113
+ if is_less:
114
+ left = mid + 1
115
+ else:
116
+ right = mid
117
+ return left
118
+
119
+
120
+ def _py_upper_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> int:
121
+ left = 0
122
+ right = len(arr)
123
+ while left < right:
124
+ mid = left + (right - left) // 2
125
+ mid_val = arr[mid]
126
+ is_less = comp(val, mid_val) if comp else (val < mid_val)
127
+ if is_less:
128
+ right = mid
129
+ else:
130
+ left = mid + 1
131
+ return left
132
+
133
+
134
+ def _py_binary_search(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> bool:
135
+ if not arr:
136
+ return False
137
+ idx = _py_lower_bound(arr, val, comp)
138
+ if idx < len(arr):
139
+ elem = arr[idx]
140
+ if comp:
141
+ return not comp(elem, val) and not comp(val, elem)
142
+ return elem == val
143
+ return False
144
+
145
+
146
+ def _py_equal_range(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None) -> tuple[int, int]:
147
+ return _py_lower_bound(arr, val, comp), _py_upper_bound(arr, val, comp)
148
+
149
+
150
+ # ----------------- Public API Interfaces -----------------
151
+
152
+ def next_permutation(arr: list, use_rust: bool = True) -> bool:
153
+ """
154
+ Rearranges elements in-place to the next lexicographically greater permutation.
155
+
156
+ If the next permutation exists, rearranges elements and returns True.
157
+ Otherwise, reverses the array to the smallest ascending order and returns False.
158
+
159
+ Args:
160
+ arr: The list to modify in-place.
161
+ use_rust: Whether to use the compiled Rust backend (default: True).
162
+
163
+ Returns:
164
+ True if next permutation exists, False otherwise.
165
+
166
+ Time Complexity:
167
+ O(n) where n is len(arr)
168
+ """
169
+ if use_rust and RUST_AVAILABLE:
170
+ return _rust_next_permutation(arr)
171
+ return _py_next_permutation(arr)
172
+
173
+
174
+ def prev_permutation(arr: list, use_rust: bool = True) -> bool:
175
+ """
176
+ Rearranges elements in-place to the next lexicographically smaller permutation.
177
+
178
+ If the previous permutation exists, rearranges elements and returns True.
179
+ Otherwise, reverses the array to the largest descending order and returns False.
180
+
181
+ Args:
182
+ arr: The list to modify in-place.
183
+ use_rust: Whether to use the compiled Rust backend (default: True).
184
+
185
+ Returns:
186
+ True if prev permutation exists, False otherwise.
187
+
188
+ Time Complexity:
189
+ O(n) where n is len(arr)
190
+ """
191
+ if use_rust and RUST_AVAILABLE:
192
+ return _rust_prev_permutation(arr)
193
+ return _py_prev_permutation(arr)
194
+
195
+
196
+ def nth_element(arr: list, nth: int, use_rust: bool = True) -> None:
197
+ """
198
+ Partitions the list in-place so that the element at index `nth` is the one
199
+ that would be there if the list were completely sorted.
200
+
201
+ All elements preceding `nth` are partitioned to be less than or equal to `nth`.
202
+ All elements succeeding `nth` are partitioned to be greater than or equal to `nth`.
203
+ Does not guarantee sorted order of the surrounding elements.
204
+
205
+ Args:
206
+ arr: The list to modify in-place.
207
+ nth: The index that should contain the sorted element.
208
+ use_rust: Whether to use the compiled Rust backend (default: True).
209
+
210
+ Time Complexity:
211
+ O(n) average case
212
+ """
213
+ if use_rust and RUST_AVAILABLE:
214
+ _rust_nth_element(arr, nth)
215
+ else:
216
+ _py_nth_element(arr, nth)
217
+
218
+
219
+ def partition(arr: list, predicate: Callable[[Any], bool], use_rust: bool = True) -> int:
220
+ """
221
+ Reorders the elements in the list in-place such that all elements for which
222
+ `predicate` returns True precede all elements for which it returns False.
223
+
224
+ Does not guarantee stable relative ordering.
225
+
226
+ Args:
227
+ arr: The list to modify in-place.
228
+ predicate: A callable returning True or False for each element.
229
+ use_rust: Whether to use the compiled Rust backend (default: True).
230
+
231
+ Returns:
232
+ The boundary index pointing to the first element that returned False.
233
+
234
+ Time Complexity:
235
+ O(n) where n is len(arr)
236
+ """
237
+ if use_rust and RUST_AVAILABLE:
238
+ return _rust_partition(arr, predicate)
239
+ return _py_partition(arr, predicate)
240
+
241
+
242
+ def lower_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> int:
243
+ """
244
+ Returns the index of the first element in the range that does not compare less than `val`.
245
+
246
+ Args:
247
+ arr: The sorted list to search.
248
+ val: The value to search for.
249
+ comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
250
+ use_rust: Whether to use the compiled Rust backend (default: True).
251
+
252
+ Returns:
253
+ The index of the first element that is >= val, or len(arr) if not found.
254
+
255
+ Time Complexity:
256
+ O(log n)
257
+ """
258
+ if use_rust and RUST_AVAILABLE:
259
+ return _rust_lower_bound(arr, val, comp)
260
+ return _py_lower_bound(arr, val, comp)
261
+
262
+
263
+ def upper_bound(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> int:
264
+ """
265
+ Returns the index of the first element in the range that compares greater than `val`.
266
+
267
+ Args:
268
+ arr: The sorted list to search.
269
+ val: The value to search for.
270
+ comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
271
+ use_rust: Whether to use the compiled Rust backend (default: True).
272
+
273
+ Returns:
274
+ The index of the first element that is > val, or len(arr) if not found.
275
+
276
+ Time Complexity:
277
+ O(log n)
278
+ """
279
+ if use_rust and RUST_AVAILABLE:
280
+ return _rust_upper_bound(arr, val, comp)
281
+ return _py_upper_bound(arr, val, comp)
282
+
283
+
284
+ def binary_search(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> bool:
285
+ """
286
+ Checks if a value is present in the sorted range.
287
+
288
+ Args:
289
+ arr: The sorted list to search.
290
+ val: The value to search for.
291
+ comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
292
+ use_rust: Whether to use the compiled Rust backend (default: True).
293
+
294
+ Returns:
295
+ True if the element equivalent to val is found, False otherwise.
296
+
297
+ Time Complexity:
298
+ O(log n)
299
+ """
300
+ if use_rust and RUST_AVAILABLE:
301
+ return _rust_binary_search(arr, val, comp)
302
+ return _py_binary_search(arr, val, comp)
303
+
304
+
305
+ def equal_range(arr: list, val: Any, comp: Callable[[Any, Any], bool] = None, use_rust: bool = True) -> tuple[int, int]:
306
+ """
307
+ Returns the range of elements equivalent to a given value.
308
+
309
+ Args:
310
+ arr: The sorted list to search.
311
+ val: The value to search for.
312
+ comp: Optional custom binary comparator Callable(a, b) defining custom less-than.
313
+ use_rust: Whether to use the compiled Rust backend (default: True).
314
+
315
+ Returns:
316
+ A tuple (lower_bound_index, upper_bound_index) defining the range of equivalent elements.
317
+
318
+ Time Complexity:
319
+ O(log n)
320
+ """
321
+ if use_rust and RUST_AVAILABLE:
322
+ return _rust_equal_range(arr, val, comp)
323
+ return _py_equal_range(arr, val, comp)
324
+
325
+
326
+ __all__ = [
327
+ 'next_permutation', 'prev_permutation', 'nth_element', 'partition',
328
+ 'lower_bound', 'upper_bound', 'binary_search', 'equal_range',
329
+ 'RUST_AVAILABLE'
330
+ ]
@@ -248,7 +248,7 @@ class stl_map:
248
248
  """
249
249
  if not isinstance(other, stl_map):
250
250
  return False
251
-
251
+
252
252
  self_data = dict(self._impl.get_data()) if self._is_rust else self._impl._data
253
253
  other_data = dict(other._impl.get_data()) if other._is_rust else other._impl._data
254
254
  return self_data == other_data
@@ -294,5 +294,4 @@ class stl_map:
294
294
  return new_map
295
295
 
296
296
 
297
-
298
297
  __all__ = ['stl_map']
@@ -191,7 +191,7 @@ class priority_queue:
191
191
  return False
192
192
  if self._comparator != other._comparator:
193
193
  return False
194
-
194
+
195
195
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
196
196
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
197
197
  return self_data == other_data
@@ -224,5 +224,4 @@ class priority_queue:
224
224
  return new_pq
225
225
 
226
226
 
227
-
228
227
  __all__ = ['priority_queue']
@@ -197,7 +197,7 @@ class queue:
197
197
  """
198
198
  if not isinstance(other, queue):
199
199
  return False
200
-
200
+
201
201
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
202
202
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
203
203
  return self_data == other_data
@@ -230,5 +230,4 @@ class queue:
230
230
  return new_queue
231
231
 
232
232
 
233
-
234
233
  __all__ = ['queue']
@@ -218,14 +218,14 @@ class stl_set:
218
218
  """
219
219
  if not isinstance(other, stl_set):
220
220
  return False
221
-
221
+
222
222
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
223
223
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
224
-
224
+
225
225
  # BTreeSet elements are sorted, so direct list equality works for sorted comparison
226
226
  if self._is_rust and other._is_rust:
227
227
  return self_data == other_data
228
-
228
+
229
229
  return set(self_data) == set(other_data)
230
230
 
231
231
  def __iter__(self) -> TypingIterator[T]:
@@ -267,5 +267,4 @@ class stl_set:
267
267
  return new_set
268
268
 
269
269
 
270
-
271
270
  __all__ = ['stl_set']
@@ -180,7 +180,7 @@ class stack:
180
180
  """
181
181
  if not isinstance(other, stack):
182
182
  return False
183
-
183
+
184
184
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
185
185
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
186
186
  return self_data == other_data
@@ -213,5 +213,4 @@ class stack:
213
213
  return new_stack
214
214
 
215
215
 
216
-
217
216
  __all__ = ['stack']
@@ -336,7 +336,7 @@ class vector:
336
336
  """
337
337
  if not isinstance(other, vector):
338
338
  return False
339
-
339
+
340
340
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
341
341
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
342
342
  return self_data == other_data
@@ -353,7 +353,7 @@ class vector:
353
353
  """
354
354
  self_data = self._impl.get_data() if self._is_rust else self._impl._data
355
355
  other_data = other._impl.get_data() if other._is_rust else other._impl._data
356
-
356
+
357
357
  min_size = min(len(self_data), len(other_data))
358
358
  for i in range(min_size):
359
359
  if self_data[i] < other_data[i]:
@@ -402,5 +402,4 @@ class vector:
402
402
  return new_vector
403
403
 
404
404
 
405
-
406
405
  __all__ = ['vector']
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes