Skip to content

Commit 75682d7

Browse files
committed
main
1 parent 834eb27 commit 75682d7

File tree

3 files changed

+100
-33
lines changed

3 files changed

+100
-33
lines changed

docs/document/Lua/docs/String.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# String
2+
3+
## Pattern Matching
4+
5+
### Range of Occurrence
6+
7+
- parameters
8+
- `pattern: string | number`: pattern to find, may include capture groups
9+
- `init?: int`: the index to start searching
10+
- `plain?: boolean`: whether to match in literal
11+
12+
- returns
13+
- `start`: start index of the first match on **the whole pattern**
14+
- `tail`: start index of the first match on **the whole pattern**(do not use `end` as variable name, it's reserved keyword)
15+
- `...matches`: arbitrary number of captured groups that can be unpacked to variables
16+
17+
```lua
18+
local text = '<tag>content</tag>'
19+
20+
-- find range of first occurrence
21+
-- and its captured groups, kind of useless though
22+
local start, tail, tag, content = text:find('<(%w+)>(%w+)</%w+>')
23+
```
24+
25+
### Replace
26+
27+
`string.gsub`: replace all occurrences
28+
29+
- parameters
30+
- `pattern: string | number`: pattern to replace
31+
- `repl: string | number | function | table`
32+
- `string`: may use `%n` to reference capture groups by index `n` to transform from groups
33+
- `fun(match: string): string`: to replace the occurrence by tranformed string from the match
34+
- `table`: a finite pairs for match(key) and replacement(value)
35+
- `n?: int`: max count of substitutions could be made
36+
37+
- returns
38+
- `text`: substituted string
39+
- `count`: substitution count made
40+
41+
```lua
42+
local text = 'snake_case_is_awful'
43+
44+
local sub, count = text:gsub('_', '-') -- snake-case-is-awful, 3
45+
46+
-- transform by captured groups
47+
local sub, count = text:gsub('(%l+)_(%l+)', '%1-%2', 1) -- snake-case_is_awful, 1
48+
49+
-- capitalize word for 2 occurrences
50+
local sub, count = text:gsub('%l+', function(match)
51+
---@cast match string
52+
local cap = match:sub(1, 1):upper()
53+
return cap .. match:sub(2)
54+
end, 2) -- Snake_Case_is_awful, 2
55+
56+
local sub, count = text:gsub('%l+', {
57+
snake = 'python',
58+
_case = '',
59+
}) -- python_case_is_awful, 4
60+
-- because the table were tried anyway and got nil when key is not registered
61+
```

docs/document/Modern CSharp/docs/Parallel Programming/Parallel Utils/Parallel Loop.md

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Parallel Loop
22

3-
`Parallel` static class provides utilities based on `Task` to perform parallel enumerations, all parallel operation are shipped with a `Task`
3+
`Parallel` static class provides utilities based on `Task` to perform parallel enumerations, all parallel operation are shipped within a `Task`
44

55
- `Parallel.For`: range based parallel enumerations, an simulation of `for` statement
66
- `Parallel.ForEach`: parallel enumerations for `IEnumerable` and `IAsyncEnumerable`
7-
- async counterpart of `For` and `ForEach`
7+
- async counterparts of `For` and `ForEach`
88
- optionally run with a `ParallelOptions`: to specify cancellation token, paralleism degree and task scheduler.
99
- access state of entire loop by a `ParallelLoopState` parameter in callback.
1010

11-
Additionally an `Invoke` exists to run action in parallel.
11+
Additionally an `Invoke` exists to run actions in parallel.
1212

1313
- `Parallel.Invoke`: invoke multiple actions in parallel
1414

@@ -23,8 +23,7 @@ var files = Directory.GetFiles(@"C:/Users/User/Projects/nix-config", "*", Search
2323
long totalSize = 0;
2424

2525
Parallel.For(0, files.Length, idx => {
26-
FileInfo info = new(files[idx]);
27-
Interlocked.Add(ref totalSize, info.Length); // [!code highlight]
26+
Interlocked.Add(ref totalSize, new FileInfo(files[idx]).Length); // [!code highlight]
2827
});
2928

3029
Console.WriteLine(totalSize);
@@ -33,13 +32,12 @@ Console.WriteLine(totalSize);
3332
## ForEach
3433

3534
```cs
36-
string[] files = Directory.GetFiles(@"~/projects/", "*", SearchOption.AllDirectories);
35+
string[] files = Directory.GetFiles(@"C:/Users/User/Projects/nix-config", "*", SearchOption.AllDirectories);
3736

3837
long totalSize = 0;
3938

4039
Parallel.ForEach(files, f => {
41-
FileInfo info = new(f);
42-
Interlocked.Add(ref totalSize, info.Length); // [!code highlight]
40+
Interlocked.Add(ref totalSize, new FileInfo(f).Length); // [!code highlight]
4341
});
4442

4543
Console.WriteLine(totalSize);
@@ -52,7 +50,7 @@ Console.WriteLine(totalSize);
5250
```cs
5351
int[] numbers = [.. Enumerable.Range(1, 10)];
5452

55-
Parallel.ForEach(Range(1,numbers.Length , 2), idx => {
53+
Parallel.ForEach(Range(1, numbers.Length, 2), idx => {
5654
_ = numbers[idx]; // [!code highlight]
5755
});
5856

@@ -117,10 +115,10 @@ dotnet run | sls \b123\b
117115
```
118116

119117
> [!NOTE]
120-
> `ShouldExitCurrentIteration` would be true after `Stop()` or `Break()` or any exception was thrown.
118+
> `state.ShouldExitCurrentIteration` would be true after `state.Stop()` or `state.Break()` or any exception was thrown.
121119
122120
> [!TIP]
123-
> Additionally you could use `IsStopped` and `IsExceptional` to coordinate in other running iterations when `Stop()` was called or any exception was thrown from any iteration.
121+
> Additionally you could use `state.IsStopped` and `state.IsExceptional` to coordinate in other running iterations when `state.Stop()` was called or any exception was thrown from any iteration.
124122
125123
## Exception Handling
126124

@@ -134,11 +132,11 @@ try {
134132
Console.WriteLine(n);
135133

136134
if (int.IsOddInteger(n))
137-
throw new Exception(); // multiple thread would throw this
135+
throw new Exception(); // multiple threads would throw this // [!code highlight]
138136
});
139137
} catch (AggregateException ex) {
140138
ex.Handle(iex => {
141-
Console.WriteLine(iex.Message); // write this for multiple times for thrown from multiple threads
139+
Console.WriteLine(iex.Message); // write this for multiple times for thrown from multiple threads // [!code highlight]
142140
return true;
143141
});
144142
}
@@ -174,29 +172,29 @@ try {
174172
_ => { // [!code highlight]
175173
while (true) // [!code highlight]
176174
cts.Token.ThrowIfCancellationRequested(); // [!code highlight]
177-
}
178-
); // [!code highlight]
175+
} // [!code highlight]
176+
);
179177
} catch (AggregateException ex) {
180178
ex.Handle(iex => {
181-
if (iex is OperationCanceledException) {
182-
// not reachable
183-
Console.WriteLine($"{nameof(OperationCanceledException)} was caught by {nameof(AggregateException)}");
184-
return true;
185-
}
179+
if (iex is OperationCanceledException) { // [!code warning]
180+
// not reachable because the cancellation would succeeded anyway // [!code warning]
181+
Console.WriteLine($"{nameof(OperationCanceledException)} was caught by {nameof(AggregateException)}"); // [!code warning]
182+
return true; // [!code warning]
183+
} // [!code warning]
186184
return false;
187185
});
188-
} catch (OperationCanceledException) { // [!code highlight]
186+
} catch (OperationCanceledException) {
189187
// would hit here since cancellation should be succeeded // [!code highlight]
190188
Console.WriteLine($"{nameof(OperationCanceledException)} was propagated directly"); // [!code highlight]
191-
} // [!code highlight]
189+
}
192190
```
193191

194192
## Performance Enhancement
195193

196194
### Thread-Local Storage
197195

198-
If one could calculate partially on **each worker thread**(the thread manages a batch of iterations), and finally add up all partial results to the target variable, it could be much more efficient than contenting one single variable from threads.
199-
Such approach is call **Thread-Local Storage**, a dedicated storage target for each worker thread.
196+
If one could calculate partially on **each worker thread**(the thread manages a batch of iterations), and finally add up all partial results to the target variable, it could be much more efficient than contenting one single variable from each iteration.
197+
Such approach is called **Thread-Local Storage**, a dedicated storage target for each worker thread.
200198
The design is pretty similar to `Enumerable.Aggregate` that folds calculation base on a given initial value on each iteration.
201199

202200
```cs
@@ -221,7 +219,7 @@ Console.WriteLine(size);
221219
### Partitioning
222220

223221
Partitioning is a trade-off solution when **invoking callback delegates in parallel loop is way too expensive** and **the operation within the delegate body is relatively fast enough**.
224-
So one can partition items from source with specified count into **ranges** and process each range **within a same thread**(because each operation is fast enough), so this reduces the cost of involing delegate callback by reducing the thread count started by the loop.
222+
So one can partition items from source with specified count into **ranges** and process each range **within a same thread**(because each operation is fast enough), so this reduces the cost of invoking delegate callback by reducing the thread count started by the loop.
225223

226224
> [!NOTE]
227225
>`Partitioner` requires collections **with indexer** to work with, it's the only way to represent a range.
@@ -230,7 +228,7 @@ So one can partition items from source with specified count into **ranges** and
230228
// calculating sum of a large array is a good example for partitioning
231229
// for it has simple operation on adding up
232230
// and to avoid callback on each iteration
233-
// optionally you could avoid resource contention by Thread-Local storage
231+
// optionally you could reduce resource contention by Thread-Local storage
234232
235233
int[] source = Enumerable.Range(1, 1000 * 1000).ToArray();
236234

@@ -243,25 +241,26 @@ Parallel.ForEach(
243241
() => 0L,
244242
(range, _, sum) => {
245243
var (start, end) = range; // unpack the tuple // [!code highlight]
246-
for (int i = start; i < end; i++) {
247-
sum = checked(sum + source[i]);
248-
}
244+
245+
for (int i = start; i < end; i++) // synchronous loop on range instead
246+
sum = checked(sum + source[i]); // a fairly simple operation // [!code highlight]
247+
249248
return sum;
250249
},
251250
sum => Interlocked.Add(ref sumOfArray, sum)
252251
);
253252

254253
Console.WriteLine(sumOfArray);
255254

256-
// you can direct sum this using linq // [!code error]
257-
// because it returns int which might overflow for such a large // [!code error]
255+
// you can't directly sum this using linq // [!code error]
256+
// because it returns int which might overflow for such a large collection // [!code error]
258257
Console.WriteLine(source.Sum() is int); // System.OverflowException // [!code error]
259258
```
260259

261260
## Invoke
262261

263262
`Parallel.Invoke` is not really a loop, but I can't find a appropriate place to introduce it.
264-
It simply run multiple actions in a parallel manner as an blocking operation, no async counterpart exist.
263+
It simply run multiple actions in a parallel manner as an blocking operation, no async counterpart exists.
265264

266265
```cs
267266
// blocking operation
@@ -270,5 +269,11 @@ Parallel.Invoke(
270269
() => Console.WriteLine(2),
271270
() => Console.WriteLine(3),
272271
() => Console.WriteLine(4)
273-
); // order is not guaranteed
272+
);
273+
274+
// order is not guaranteed
275+
// 1
276+
// 3
277+
// 2
278+
// 4
274279
```

docs/services/DocumentService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const documentMap = {
2929
'Entity Framework Core': { icon: '🗿', description: '' },
3030
'HTML & CSS': { icon: '😬', description: '' },
3131
PowerShell: { icon: '🐚', description: '' },
32+
Lua: { icon: '🌝' },
3233
} as const satisfies DocumentInfo;
3334

3435
export type DocumentName = keyof typeof documentMap;

0 commit comments

Comments
 (0)