diff --git a/docs/document/Articles/docs/Integrating Cygwin with VSCode.md b/docs/document/Articles/docs/Integrating Cygwin with VSCode.md new file mode 100644 index 00000000..3171ed90 --- /dev/null +++ b/docs/document/Articles/docs/Integrating Cygwin with VSCode.md @@ -0,0 +1,66 @@ +# Integrating Cygwin with VSCode in Windows + +## Installation + +Follow guide from [Cygwin](https://cygwin.com/). + +## Add terminal profile in `settings.json` + +Add new profile for cygwin, this will register a new option when we choose to launch a new integrated terminal. + +```json{15, 19} +{ + "terminal.integrated.profiles.windows": { + "PowerShell": { + "source": "PowerShell", + "icon": "terminal-powershell" + }, + "Command Prompt": { + "path": ["${env:windir}\\Sysnative\\cmd.exe", "${env:windir}\\System32\\cmd.exe"], + "args": [], + "icon": "terminal-cmd" + }, + "Git Bash": { + "source": "Git Bash" + }, + "Cygwin": { + "path": "C:\\cygwin64\\bin\\bash.exe", + "args": ["--login"], + "overrideName": true + } + }, +} +``` + +Then we got a new option to create a integrated terminal. +![cygwin-option](../pics/cygwin-profile.png) + +:::info +For more information: [Terminal Profiles](https://code.visualstudio.com/docs/terminal/profiles#_cygwin). +::: + +## Change default working directory of cygwin in `.bashrc` + +The default working directory of cygwin is `{installation-path}\home\{username}` like `C:\cygwin64\home\anon`. + +You might like to launch cygwin with working directory as the root of current user. + +- Open cygwin, make sure you're at `~` + +```bash +cd ~ +``` + +- Execute this line into `.bashrc`. + +```bash +touch .bashrc && echo 'cd /cygdrive/c/users/{username}' >> .bashrc +``` + +- Check the content is successfully appended. + +```bash +cat .bashrc +``` + +- Launch a new cygwin instance, it will start at your user root. diff --git a/docs/document/Articles/pics/cygwin-profile.png b/docs/document/Articles/pics/cygwin-profile.png new file mode 100644 index 00000000..530abc03 Binary files /dev/null and b/docs/document/Articles/pics/cygwin-profile.png differ diff --git a/docs/document/CesiumJS/docs/1. Init your cesium project with vite.md b/docs/document/CesiumJS/docs/1. Init your cesium project with vite.md new file mode 100644 index 00000000..a5f36e3f --- /dev/null +++ b/docs/document/CesiumJS/docs/1. Init your cesium project with vite.md @@ -0,0 +1,72 @@ +# Init your cesium project with vite + +## Create a latest vue3 project + +Redirect to your working directory, run + +```bash +pnpm create vue@latest +``` + +Follow the instruction, select options based on your need.(It's recommended to work with `typescript`, `vite` and `Vue Router`) + +:::info +For more information: [Vue3 Tooling](https://vuejs.org/guide/scaling-up/tooling.html#project-scaffolding) +::: + +## Add [cesium vite plugin](/~https://github.com/s3xysteak/vite-plugin-cesium-build) + +```bash +pnpm add -D vite-plugin-cesium-build +``` + +```ts{9} +import { fileURLToPath, URL } from 'node:url'; +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import vueJsx from '@vitejs/plugin-vue-jsx'; +import cesium from 'vite-plugin-cesium-build'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), vueJsx(), cesium()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}); +``` + +## Add a earth at `App.vue` + +Delete auto-generated template, add following code. + +```vue + + + + + +``` + +Start the server. + +```bash +pnpm dev +``` + +:::warning +Check scripts in `package.json` to make sure you use the right command, auto-generated scripts might differ from versions. +::: diff --git a/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/CSharpDesignPatternsDemo.csproj b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/CSharpDesignPatternsDemo.csproj index ad9fcfe2..e769a424 100644 --- a/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/CSharpDesignPatternsDemo.csproj +++ b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/CSharpDesignPatternsDemo.csproj @@ -6,9 +6,11 @@ enable enable preview + Release + diff --git a/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Program.cs b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Program.cs index 45ca91e6..956e127a 100644 --- a/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Program.cs +++ b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Program.cs @@ -2,27 +2,96 @@ using CSharpDesignPatternsDemo.Structural; using CSharpDesignPatternsDemo.Creational; using System.Numerics; +using System.Text.Json; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Validators; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Columns; -var p1 = 20 + 30.Percentage(); -var p2 = 2 - 50f.Percentage(); -var p3 = 4 * 25d.Percentage(); -var p4 = 1 / 66m.Percentage(); -var p11 = 30.Percentage() + 20; -var p12 = 2f.Percentage() - 50; -var p13 = 4d.Percentage() * 25; -var p14 = 1m.Percentage() / 66; -Print(p1, p2, p3, p4, p11, p12, p13, p14); +// var enemyCollection = EnemyCollection.Create(10, () => (Random.Shared.Next(18, 36), Random.Shared.NextDouble())); +// Magic.Freeze(enemyCollection); +// enemyCollection[2].Agility = 250; +// Console.WriteLine(enemyCollection._agility![2]); +// var enemies = new EnemySpan(5, () => (1, 2)); +// foreach (ref var e in enemies.Agility) +// { +// e = 250; +// } +// foreach (var e in enemies._agility!) +// { +// Console.WriteLine(e); +// } -static void Print(params object[] objects) -{ - objects.ToList().ForEach(Console.WriteLine); -} +var config = new ManualConfig() + .WithOptions(ConfigOptions.DisableOptimizationsValidator) + .AddValidator(JitOptimizationsValidator.DontFailOnError) + .AddLogger(ConsoleLogger.Default) + .AddColumnProvider(DefaultColumnProviders.Instance); + +BenchmarkRunner.Run(config); -Span span = Enumerable.Range(1, 100).ToArray().AsSpan(); -Random.Shared.Shuffle(span); -var condition = span is [var first, _, .. var _]; // always true -condition.Out(); -static class OutExtension +[MemoryDiagnoser] +public class AoS_SoA { - public static void Out(this object o) => Console.WriteLine(o); -} \ No newline at end of file + private Enemy[]? _aos; + private EnemyCollection? _soa; + private EnemyCollection2 _soaS; + + private EnemySpan _soaSpan; + [Params(10000)] public int _size; + + [GlobalSetup] + public void SetUp() + { + _aos = Enumerable.Range(1, _size) + .Select(x => new Enemy() { Age = Random.Shared.Next(18, 36), Agility = Random.Shared.NextDouble() }) + .ToArray(); + _soa = EnemyCollection.Create(_size, () => (Random.Shared.Next(18, 36), Random.Shared.NextDouble())); + _soaS = EnemyCollection2.Create(_size, () => (Random.Shared.Next(18, 36), Random.Shared.NextDouble())); + _soaSpan = new(_size, () => (Random.Shared.Next(18, 36), Random.Shared.NextDouble())); + } + [Benchmark] + public void Freeze_AoS() + { + for (int i = 0; i < _aos!.Length; i++) + { + ref Enemy e = ref _aos![i]; + e.Agility = 0; + } + } + [Benchmark] + public void Freeze_SoA() + { + foreach (var e in _soa!) + { + e.Agility = 0; + } + } + [Benchmark] + public void Freeze_SoA_Enumerator() + { + var e = _soa!._agility!.GetEnumerator2(); + while (e.MoveNext()) + { + e.Current = 0; + } + } + [Benchmark] + public void Freeze_SoA_Struct() + { + foreach (var e in _soaS) + { + e.Agility = 0; + } + } + [Benchmark] + public void Freeze_SoA_Span() + { + foreach (ref var e in _soaSpan.Agility) + { + e = 0; + } + } +} diff --git a/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Structural/5. Proxy/4. Composite Proxy - AoS and SoA.cs b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Structural/5. Proxy/4. Composite Proxy - AoS and SoA.cs new file mode 100644 index 00000000..144d85d7 --- /dev/null +++ b/docs/document/Csharp Design Patterns/CsharpDesignPatternsDemo/Structural/5. Proxy/4. Composite Proxy - AoS and SoA.cs @@ -0,0 +1,245 @@ +using System.Collections; +using System.Runtime.CompilerServices; +using Microsoft.Diagnostics.Tracing; + +namespace CSharpDesignPatternsDemo.Structural; + +struct Enemy +{ + public int Age { get; set; } + public double Agility { get; set; } +} + +class EnemyCollection(int size) +{ + internal int[]? _age; + internal double[]? _agility; + private readonly int _size = size; + public EnemyShadow this[int index] => new(this, index); + public static EnemyCollection Create(int size, Func<(int age, double agility)>? generator = default) + { + var result = new EnemyCollection(size) + { + _age = new int[size], + _agility = new double[size] + }; + if (generator is { }) + { + for (int i = 0; i < size; i++) + (result._age[i], result._agility[i]) = generator(); + } + return result; + } + + public ref struct Enumerator + { + private readonly EnemyCollection _enemies; + private int _index; + public Enumerator(EnemyCollection enemy) + { + _enemies = enemy; + _index = -1; + } + public readonly EnemyShadow Current => _enemies[_index]; + + public bool MoveNext() + { + int index = _index + 1; + if (index < _enemies._size) + { + _index = index; + return true; + } + return false; + } + } + public Enumerator GetEnumerator() => new(this); +} + +readonly ref struct EnemyShadow +{ + private readonly int _index; + private readonly EnemyCollection _enemies; + public EnemyShadow(EnemyCollection enemies, int index) => (_enemies, _index) = (enemies, index); + public ref int Age => ref _enemies._age![_index]; + public ref double Agility => ref _enemies._agility![_index]; +} +static class Magic +{ + public struct ArrayEnumerator + { + T[] _arr; + int _index; + public ref T Current => ref _arr[_index]; + public ArrayEnumerator(in T[] arr) + { + _arr = arr; + _index = -1; + } + public bool MoveNext() + { + int index = _index + 1; + if (index < _arr.Length) + { + _index = index; + return true; + } + return false; + } + } + public static ArrayEnumerator GetEnumerator2(this T[] arr) + { + return new(in arr); + } + // public static void Freeze(Enemy[] enemies) + // { + // foreach (var e in enemies) e.Agility = 0; + // } + + // public static void Freeze(IEnumerable enemies) + // { + // foreach (var e in enemies) e.Agility = 0; + // } + public static void Freeze(EnemyCollection enemies) + { + foreach (var e in enemies) e.Agility = 0; + } + public static void Age(EnemyCollection enemies, int count = 1) + { + foreach (var e in enemies) e.Age += count; + } + // public static void Age(Enemy[] enemies, int count = 1) + // { + // foreach (var e in enemies) e.Age += count; + // } +} + + +struct EnemyCollection2(int size) +{ + internal int[]? _age; + internal double[]? _agility; + private readonly int _size = size; + public EnemyShadow2 this[int index] => new(this, index); + public static EnemyCollection2 Create(int size, Func<(int age, double agility)>? generator = default) + { + var result = new EnemyCollection2(size) + { + _age = new int[size], + _agility = new double[size] + }; + if (generator is { }) + { + for (int i = 0; i < size; i++) + (result._age[i], result._agility[i]) = generator(); + } + return result; + } + + public ref struct Enumerator + { + private readonly EnemyCollection2 _enemies; + private int _index; + public Enumerator(EnemyCollection2 enemy) + { + _enemies = enemy; + _index = -1; + } + public readonly EnemyShadow2 Current => _enemies[_index]; + + public bool MoveNext() + { + int index = _index + 1; + if (index < _enemies._size) + { + _index = index; + return true; + } + return false; + } + + } + public Enumerator GetEnumerator() => new(this); +} +readonly ref struct EnemyShadow2 +{ + private readonly int _index; + private readonly EnemyCollection2 _enemies; + public EnemyShadow2(EnemyCollection2 enemies, int index) => (_enemies, _index) = (enemies, index); + public ref int Age => ref _enemies._age![_index]; + public ref double Agility => ref _enemies._agility![_index]; +} + +struct EnemySpan(int size) +{ + internal int[]? _age = new int[size]; + internal double[]? _agility = new double[size]; + internal readonly Span Age => _age.AsSpan(); + internal readonly Span Agility => _agility.AsSpan(); + int _size = size; + + public EnemySpan(int size, Func<(int age, double agility)>? generator = default) : this(size) + { + if (generator is { }) + { + for (int i = 0; i < size; i++) + (_age![i], _agility![i]) = generator(); + } + } + public Enumerator GetEnumerator() => new(this); + public ref struct Enumerator + { + private EnemySpan _enemies; + private int _index; + public Enumerator(EnemySpan enemy) + { + _enemies = enemy; + _index = -1; + } + public EnemyShadow3 Current => new(ref _enemies.Age[_index], ref _enemies.Agility[_index]); + + public bool MoveNext() + { + int index = _index + 1; + if (index < _enemies._size) + { + _index = index; + return true; + } + return false; + } + } +} +ref struct EnemyShadow3 +{ + private static readonly int[] a = { 1 }; + private static readonly double[] b = { 1 }; + + private readonly int _index; + private readonly EnemySpan _enemies; + public EnemyShadow3(ref EnemySpan enemies, int index) => (_enemies, _index) = (enemies, index); + public EnemyShadow3(ref int age, ref double agility) + { + _age = age; + _agility = agility; + } + private ref int _age = ref a[0]; + private ref double _agility = ref b[0]; + public ref int Age + { + get + { + // if (!_enemies.Equals(default)) return ref _enemies.Age[_index]; + return ref _age; + } + } + + public ref double Agility + { + get + { + // if (!_enemies.Equals(default)) return ref _enemies.Agility[_index]; + return ref _agility; + } + } +} \ No newline at end of file diff --git a/docs/document/Csharp Design Patterns/docs/Structural/6. Proxy.md b/docs/document/Csharp Design Patterns/docs/Structural/6. Proxy.md index ae422665..ef6e7e4e 100644 --- a/docs/document/Csharp Design Patterns/docs/Structural/6. Proxy.md +++ b/docs/document/Csharp Design Patterns/docs/Structural/6. Proxy.md @@ -221,3 +221,47 @@ static class PercentageExtension } } ``` + +## Composite Proxy - `Aos/SoA` + +In some scenarios we do enumerations to modify values of a collection of certain structured type. +Assuming we are developing a game, `Enemy` is an entity model and we can perform magic on an collection of them. + +An array of entity model `Entity` can be called as `Array of Structure(AoS)`. + +```cs +var enemies = Enumerable.Range(1, 100) + .Select(_ => new Enemy() { Age = Random.Shared.Next(18, 36), Agility = Random.Shared.NextDouble() }) + .ToArray(); + +Magic.Freeze(enemies); + +class Enemy +{ + public int Age { get; set; } + public double Agility { get; set; } +} + +static class Magic +{ + public static void Freeze(params Enemy[] enemies) + { + foreach (var e in enemies) e.Agility = 0; + } + + public static void Freeze(IEnumerable enemies) + { + foreach (var e in enemies) e.Agility = 0; + } +} +``` + +### Problem of `AoS` + +When iterating over a field of all elements (e.g., updating all `Agility`), the memory access pattern can be non-contiguous, leading to cache misses and reduced performance. + +### Solution - `SoA` + +```cs + +``` diff --git a/docs/document/Vue3/docs/1. Create a latest vue project/1. Start with vue3 and vite.md b/docs/document/Vue3/docs/1. Create a latest vue project/1. Start with vue3 and vite.md new file mode 100644 index 00000000..cca38163 --- /dev/null +++ b/docs/document/Vue3/docs/1. Create a latest vue project/1. Start with vue3 and vite.md @@ -0,0 +1,15 @@ +# Start with vue3 and vite + +## Create a new project + +Redirect to your working directory, run + +```bash +npm create vue@latest +``` + +Follow the instruction, select options based on your need.(It's recommended to work with `typescript`, `vite` and `Vue Router`) + +:::info +For more information: [Vue3 Tooling](https://vuejs.org/guide/scaling-up/tooling.html#project-scaffolding) +::: diff --git a/docs/document/Vue3/docs/1. Create a latest vue project/2. Project structure.md b/docs/document/Vue3/docs/1. Create a latest vue project/2. Project structure.md new file mode 100644 index 00000000..691ab054 --- /dev/null +++ b/docs/document/Vue3/docs/1. Create a latest vue project/2. Project structure.md @@ -0,0 +1,15 @@ +# Project structure + +## Folder + +### First level + +- `public` stores static resources to be packed when building. Files in it can be things like an icon. +- `src` stores components, scripts, css, tests, routing configs, and more. + +```txt +. +├── node_modules +├── public +└── src +``` diff --git a/docs/document/Vue3/docs/1. Define a Component and Reuse it/1. How to define a component.md b/docs/document/Vue3/docs/2. Define a Component and Reuse it/1. How to define a component.md similarity index 100% rename from docs/document/Vue3/docs/1. Define a Component and Reuse it/1. How to define a component.md rename to docs/document/Vue3/docs/2. Define a Component and Reuse it/1. How to define a component.md diff --git a/docs/document/Vue3/docs/1. Define a Component and Reuse it/2. Bring component into scope.md b/docs/document/Vue3/docs/2. Define a Component and Reuse it/2. Bring component into scope.md similarity index 100% rename from docs/document/Vue3/docs/1. Define a Component and Reuse it/2. Bring component into scope.md rename to docs/document/Vue3/docs/2. Define a Component and Reuse it/2. Bring component into scope.md diff --git a/docs/document/Vue3/docs/2. Define a Component and Reuse it/3. Reference an DOM.md b/docs/document/Vue3/docs/2. Define a Component and Reuse it/3. Reference an DOM.md new file mode 100644 index 00000000..36dd3a9f --- /dev/null +++ b/docs/document/Vue3/docs/2. Define a Component and Reuse it/3. Reference an DOM.md @@ -0,0 +1,3 @@ +# Reference an DOM + +## `ref` diff --git a/docs/document/Vue3/docs/2. Lifecycle/1. Component Lifecycle.md b/docs/document/Vue3/docs/3. Lifecycle/1. Component Lifecycle.md similarity index 100% rename from docs/document/Vue3/docs/2. Lifecycle/1. Component Lifecycle.md rename to docs/document/Vue3/docs/3. Lifecycle/1. Component Lifecycle.md