Skip to content

Commit b13ba1a

Browse files
committed
Am i finally done?
1 parent 62fd0bf commit b13ba1a

11 files changed

Lines changed: 1183 additions & 190 deletions

=

Whitespace-only changes.

docs/Loops/iteration.md

Lines changed: 118 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
1-
[⬅ Back to Table of Contents](index.md)
1+
[⬅ Back to Table of Contents](../index.md)
22
[⬅ Back to Error](../Errors/errors.md)
33

44
# Iteration Helpers
55

6-
This page documents all user-facing iteration helpers in Pythonic, including range, enumerate, zip, reversed, loop macros, and utility functions, with concise examples.
6+
This page documents all user-facing iteration helpers in Pythonic, including range, enumerate, zip, reversed, loop helpers, and utility functions, with concise examples.
7+
8+
---
9+
10+
## Mutation Detection (Python-like Safety)
11+
12+
Starting with the latest version, all `var` container types (`list`, `set`, `dict`, `ordered_set`, `ordered_dict`, `string`) now have **Python-like mutation detection during iteration**. If you modify a container while iterating over it, a `PythonicRuntimeError` will be thrown.
13+
14+
| Behavior | Description | Example |
15+
| -------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------- |
16+
| Mutation during iteration throws | Modifying a container (append, clear, remove, etc.) while iterating throws | `for (auto x : lst) { lst.append(1); } // THROWS!` |
17+
| Normal iteration is safe | Non-mutating iteration works as expected | `for (auto x : lst) { print(x); } // OK` |
18+
| Iteration version tracking | Each container tracks a version counter that increments on mutation | `lst.get_version()` |
19+
20+
**Note:** This safety applies to all iteration methods: range-based for, `enumerate()`, `indexed()`, `each()`, `each_indexed()`, and the deprecated macros.
721

822
---
923

1024
## Range & Views
1125

1226
| Function / Macro | Description | Example |
1327
| -------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------ |
14-
| `range(end)` | Range from 0 to end-1 | `for_range(i, 10) { ... }` |
15-
| `range(start, end)` | Range from start to end-1 | `for_range(i, 1, 10) { ... }` |
16-
| `range(start, end, step)` | Range with explicit step | `for_range(i, 10, 0, -1) { ... }` |
28+
| `range(end)` | Range from 0 to end-1 | `for (auto i : range(10)) { ... }` |
29+
| `range(start, end)` | Range from start to end-1 | `for (auto i : range(1, 10)) { ... }` |
30+
| `range(start, end, step)` | Range with explicit step | `for (auto i : range(10, 0, -1)) { ... }` |
1731
| `views::take_n(r, n)` | View of first n elements | `for (auto x : views::take_n(lst, 5)) { ... }` |
1832
| `views::drop_n(r, n)` | View dropping first n elements | `for (auto x : views::drop_n(lst, 2)) { ... }` |
1933
| `views::filter_view(r, pred)` | Filtered view by predicate | `for (auto x : views::filter_view(lst, pred)) { ... }` |
@@ -25,11 +39,12 @@ This page documents all user-facing iteration helpers in Pythonic, including ran
2539

2640
## Enumerate & Zip
2741

28-
| Function / Macro | Description | Example |
29-
| ------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
30-
| `enumerate(container, start=0)` | Index/value pairs (not for pythonic::vars::var or dynamic list) | `for_enumerate(i, x, lst) { ... }` (not for pythonic::vars::var or dynamic list) |
31-
| `views::enumerate_view(r)` | Enumerated view (C++20, works with pythonic::vars::var and dynamic list) | `for (auto [i, x] : views::enumerate_view(lst)) { ... }` |
32-
| `zip(a, b, ...)` | Zip multiple containers | `for (auto [x, y] : zip(lst1, lst2)) { ... }` |
42+
| Function / Macro | Description | Example |
43+
| ------------------------------- | ---------------------------------------------------- | -------------------------------------------------------- |
44+
| `enumerate(container, start=0)` | Index/value pairs (safe with mutation detection) | `for (auto [i, x] : enumerate(lst)) { ... }` |
45+
| `indexed(container)` | Index/value pairs (alias for enumerate, class-based) | `for (auto [i, x] : indexed(lst)) { ... }` |
46+
| `views::enumerate_view(r)` | Enumerated view (C++20) | `for (auto [i, x] : views::enumerate_view(lst)) { ... }` |
47+
| `zip(a, b, ...)` | Zip multiple containers | `for (auto [x, y] : zip(lst1, lst2)) { ... }` |
3348

3449
---
3550

@@ -41,15 +56,32 @@ This page documents all user-facing iteration helpers in Pythonic, including ran
4156

4257
---
4358

44-
## Loop Macros
59+
## Class-Based Loop Helpers (Recommended)
60+
61+
These are type-safe, template-based alternatives to macros. They provide better IDE support, compile-time error checking, and integrate with mutation detection.
62+
63+
| Function | Description | Example |
64+
| ------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------ |
65+
| `each(container, func)` | Apply function to each element (early exit if func returns false) | `each(lst, [](auto& x) { print(x); });` |
66+
| `each_indexed(container, func)` | Apply function with index (early exit if func returns false) | `each_indexed(lst, [](size_t i, auto& x) { print(i, x); });` |
67+
| `indexed(container)` | Returns wrapper yielding (index, value) pairs for range-for | `for (auto [i, x] : indexed(lst)) { ... }` |
68+
| `times(n, func)` | Execute func n times, with optional index parameter | `times(10, [](size_t i) { print(i); });` |
69+
| `until(container, pred)` | Iterate until predicate returns true | `until(lst, [](auto& x) { return x == 5; });` |
70+
| `while_each(container, pred)` | Iterate while predicate returns true | `while_each(lst, [](auto& x) { return x < 5; });` |
71+
72+
---
73+
74+
## Loop Macros (Deprecated - use class-based helpers)
75+
76+
These macros are kept for backward compatibility but are **not type-safe**. Prefer the class-based helpers above.
4577

46-
| Macro | Description | Example |
47-
| ------------------------------------ | ---------------------------------------- | ---------------------------------- |
48-
| `for_each(var, container)` | Range-based for loop | `for_each(x, lst) { ... }` |
49-
| `for_index(idx, container)` | Loop with index | `for_index(i, lst) { ... }` |
50-
| `for_enumerate(idx, val, container)` | Enumerate style loop | `for_enumerate(i, x, lst) { ... }` |
51-
| `for_range(var, ...)` | Python-like for in range | `for_range(i, 10) { ... }` |
52-
| `while_true` | Infinite loop (like Python's while True) | `while_true { ... }` |
78+
| Macro | Description | Recommended Alternative |
79+
| ------------------------------------ | ---------------------------------------- | -------------------------------------------------- |
80+
| `for_each(var, container)` | Range-based for loop | `for (auto x : container) { ... }` |
81+
| `for_index(idx, container)` | Loop with index | `for (auto [i, x] : indexed(container)) { ... }` |
82+
| `for_enumerate(idx, val, container)` | Enumerate style loop | `for (auto [i, x] : enumerate(container)) { ... }` |
83+
| `for_range(var, ...)` | Python-like for in range | `for (auto i : range(...)) { ... }` |
84+
| `while_true` | Infinite loop (like Python's while True) | `while (true) { ... }` |
5385

5486
---
5587

@@ -72,45 +104,88 @@ This page documents all user-facing iteration helpers in Pythonic, including ran
72104
```cpp
73105
#include "pythonic/pythonicLoop.hpp"
74106
using namespace pythonic::loop;
107+
using namespace pythonic::vars;
75108

76109
// --- Range ---
77-
for_range(i, 5) { print(i); } // 0 1 2 3 4
78-
for_range(i, 1, 5) { print(i); } // 1 2 3 4
79-
for_range(i, 10, 0, -2) { print(i); } // 10 8 6 4 2
110+
for (auto i : range(5)) { print(i); } // 0 1 2 3 4
111+
for (auto i : range(1, 5)) { print(i); } // 1 2 3 4
112+
for (auto i : range(10, 0, -2)) { print(i); } // 10 8 6 4 2
80113

81-
// --- Enumerate ---
82-
// NOTE: for_enumerate macro is not compatible with pythonic::vars::var or dynamic list. Use enumerate_view for those.
83-
for_enumerate(i, x, std::vector<int>{10, 20, 30}) { print(i, x); }
84-
for (auto [i, x] : views::enumerate_view(list(10, 20, 30))) { print(i, x); }
114+
// --- Class-based helpers (recommended) ---
115+
var lst = list(10, 20, 30);
85116

86-
// --- Zip ---
87-
for (auto [x, y] : zip(list(1,2,3), list("a","b","c"))) { print(x, y); }
117+
// each() - clean iteration with lambdas
118+
each(lst, [](var& x) { print(x); });
119+
120+
// each() with early exit
121+
each(lst, [](var& x) -> bool {
122+
if (x.toInt() > 15) return false; // stop
123+
print(x);
124+
return true;
125+
});
88126

89-
// --- Reversed ---
90-
// Not supported for pythonic::vars::var or list. Use slicing with negative step for reverse iteration:
91-
for (auto x : list(1,2,3).slice(var(), var(), -1)) { print(x); } // 3 2 1
127+
// each_indexed() - iteration with index
128+
each_indexed(lst, [](size_t i, var& x) {
129+
print(i, ":", x);
130+
});
92131

93-
// --- Loop Macros ---
94-
for_each(x, list(1,2,3)) { print(x); }
95-
for_index(i, list(1,2,3)) { print(i, list(1,2,3)[i]); }
96-
while_true { break; }
132+
// indexed() - range-based for with index
133+
for (auto [i, x] : indexed(lst)) {
134+
print(i, x);
135+
}
136+
137+
// times() - repeat N times
138+
times(5, [](size_t i) { print("iteration", i); });
139+
times(3, []() { print("hello"); });
140+
141+
// --- Enumerate ---
142+
for (auto [i, x] : enumerate(lst)) { print(i, x); }
143+
for (auto [i, x] : enumerate(lst, 100)) { print(i, x); } // start index at 100
144+
145+
// --- Zip ---
146+
var names = list("Alice", "Bob");
147+
var ages = list(25, 30);
148+
for (auto [name, age] : zip(names, ages)) { print(name, "is", age); }
149+
150+
// --- Mutation Detection ---
151+
var mutable_lst = list(1, 2, 3);
152+
try {
153+
for (auto x : mutable_lst) {
154+
mutable_lst.append(4); // THROWS PythonicRuntimeError!
155+
}
156+
} catch (const PythonicRuntimeError& e) {
157+
print("Caught:", e.what());
158+
}
159+
160+
// Safe: mutation after iteration is fine
161+
for (auto x : mutable_lst) { print(x); }
162+
mutable_lst.append(4); // OK - iteration is done
163+
164+
// --- Reversed (for std containers) ---
165+
std::vector<int> v = {1, 2, 3};
166+
for (auto x : reversed(v)) { print(x); } // 3 2 1
167+
168+
// For var/list, use slicing with negative step instead:
169+
for (auto x : lst.slice(var(), var(), -1)) { print(x); } // 30 20 10
97170

98171
// --- Utility Functions ---
99-
print(len(list(1,2,3)));
100-
print(to_list(range(5)));
101-
print(sum(list(1,2,3)));
102-
print(min(list(1,2,3)));
103-
print(max(list(1,2,3)));
104-
print(any(list(0,1,0)));
105-
print(all(list(1,1,1)));
172+
print(len(list(1,2,3))); // 3
173+
print(to_list(range(5))); // [0,1,2,3,4]
174+
print(sum(list(1,2,3))); // 6
175+
print(min(list(1,2,3))); // 1
176+
print(max(list(1,2,3))); // 3
177+
print(any(list(0,1,0))); // true
178+
print(all(list(1,1,1))); // true
106179
```
107180
108181
---
109182
110183
## Notes
111184
112-
- All iteration helpers work with standard containers, Pythonic containers, and C++20 ranges, except reverse iteration for pythonic::vars::var/list (use .slice with negative step instead). -**Negative indices and negative step are supported in pythonic::vars::var/list slicing:** - `lst[-1]` gives the last element, `lst.slice(var(), var(), -1)` reverses the list, etc.
113-
- Loop macros provide Python-like syntax for common iteration patterns.
185+
- **Mutation detection is now enabled** for all `var` container types. Modifying during iteration throws.
186+
- **Prefer class-based helpers** (`each()`, `each_indexed()`, `indexed()`, `times()`) over macros for type safety and IDE support.
187+
- **Negative indices and negative step** are supported in `var`/list slicing for reverse iteration.
188+
- Loop macros are deprecated but kept for backward compatibility.
114189
- Views are lazy and efficient; use them for large data or pipelines.
115190
- Utility functions operate on any iterable, including ranges and views.
116191

docs/Math/math.md

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,33 @@ This page documents all user-facing math functions in Pythonic, using a clear ta
1212

1313
Many arithmetic and aggregation functions accept an optional `policy` parameter of type `Overflow`, which controls how overflows are handled:
1414

15-
| Policy | Description |
16-
| ------------------- | ----------------------------------------------------------------------------- |
17-
| `Overflow::Throw` | **Default.** Throw an exception on overflow (safe, Python-like). |
18-
| `Overflow::Promote` | Promote to a larger type on overflow (never throws, but may use bigger type). |
19-
| `Overflow::Wrap` | Wrap around on overflow (C++-like, may lose data, never throws). |
15+
| Policy | Enum Value | Description |
16+
| ------------------------ | ---------- | ------------------------------------------------------------------------------- |
17+
| `Overflow::Throw` | 0 | **Default for functions.** Throw an exception on overflow (safe, Python-like). |
18+
| `Overflow::Promote` | 1 | Promote to a larger type on overflow (never throws, but may use bigger type). |
19+
| `Overflow::Wrap` | 2 | Wrap around on overflow (C++-like, may lose data, never throws). |
20+
| `Overflow::None_of_them` | 3 | **Default for operators.** Raw C++ arithmetic (no checks, maximum performance). |
21+
22+
**Policy Selection Guide:**
23+
24+
| Use Case | Recommended Policy |
25+
| ----------------------------------- | ------------------------ |
26+
| Production code (safety first) | `Overflow::Throw` |
27+
| Scientific computing (large values) | `Overflow::Promote` |
28+
| Performance-critical inner loops | `Overflow::None_of_them` |
29+
| Embedded/systems programming | `Overflow::Wrap` |
2030

2131
**Usage Example:**
2232

2333
```cpp
24-
add(1, 2); // Uses Overflow::Throw by default
25-
add(1, 2, Overflow::Promote); // Promotes type on overflow
26-
add(1, 2, Overflow::Wrap); // Wraps on overflow
34+
add(1, 2); // Uses Overflow::Throw by default
35+
add(1, 2, Overflow::Promote); // Promotes type on overflow
36+
add(1, 2, Overflow::Wrap); // Wraps on overflow
37+
add(1, 2, Overflow::None_of_them);// Raw C++ arithmetic (fastest)
38+
39+
// Operator overloads use None_of_them by default for performance
40+
var a = 1000000, b = 1000000;
41+
var c = a * b; // Uses Overflow::None_of_them (raw C++ multiplication)
2742
```
2843
2944
---
@@ -32,22 +47,46 @@ add(1, 2, Overflow::Wrap); // Wraps on overflow
3247
3348
When using `Overflow::Promote`, types are promoted in the following order:
3449
35-
| Rank | Type |
36-
| ---- | ------------------ |
37-
| 0 | bool |
38-
| 1 | unsigned int |
39-
| 2 | int |
40-
| 3 | unsigned long |
41-
| 4 | long |
42-
| 5 | unsigned long long |
43-
| 6 | long long |
44-
| 7 | float |
45-
| 8 | double |
46-
| 9 | long double |
47-
48-
- Unsigned types are preferred if both inputs are unsigned and result is non-negative.
49-
- Signed types are used if any input is signed or result is negative.
50-
- For floating-point or division, promotion starts at float.
50+
| Rank | Type | Description |
51+
| ---- | ------------------ | --------------------------------- |
52+
| 0 | bool | Boolean (never promoted TO) |
53+
| 1 | unsigned int | Smallest unsigned integer |
54+
| 2 | int | Smallest signed integer |
55+
| 3 | unsigned long | Medium unsigned integer |
56+
| 4 | long | Medium signed integer |
57+
| 5 | unsigned long long | Largest unsigned integer |
58+
| 6 | long long | Largest signed integer |
59+
| 7 | float | Single-precision floating-point |
60+
| 8 | double | Double-precision floating-point |
61+
| 9 | long double | Extended-precision floating-point |
62+
63+
### Promotion Strategy
64+
65+
The promotion system uses different strategies based on input types:
66+
67+
| Input Types | Promotion Strategy |
68+
| ------------------- | ------------------------------------------------------------------ |
69+
| Both unsigned | Try unsigned containers (uint → ulong → ulong_long), then floating |
70+
| At least one signed | Try signed containers (int → long → long_long), then floating |
71+
| Any floating-point | Use floating containers only (float → double → long double) |
72+
73+
### Smart Fit Behavior
74+
75+
The `smart_promote()` function finds the **smallest** container that can hold the result:
76+
77+
```cpp
78+
// Both unsigned → result fits in smallest unsigned type
79+
var a = 100u, b = 200u;
80+
var result = add(a, b, Overflow::Promote); // Returns unsigned int (300)
81+
82+
// Large result → promoted to larger type
83+
var big = std::numeric_limits<int>::max();
84+
var result = add(big, 1, Overflow::Promote); // Returns long long
85+
86+
// Division always uses floating-point for precision
87+
var x = 5, y = 2;
88+
var result = div(x, y, Overflow::Promote); // Returns float (2.5)
89+
```
5190

5291
---
5392

@@ -215,11 +254,11 @@ int main()
215254

216255
var a = 10, b = 3, c = std::numeric_limits<int>::max();
217256
print(add(a, b)); // 13
218-
try
257+
try
219258
{
220259
print(add(a, c)); // overflow
221-
}
222-
catch (const pythonic::error::PythonicOverflowError& e)
260+
}
261+
catch (const pythonic::error::PythonicOverflowError& e)
223262
{
224263
print("Overflow error: ", e.what());
225264
}

0 commit comments

Comments
 (0)