Skip to content

Commit

Permalink
main
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpchen committed Feb 4, 2025
1 parent e183560 commit 97f1e4e
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/document/Articles/docs/ADB Cheat Sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ adb sideload /path/to/rom.zip

## ABI

```ps1
```sh
adb shell getprop ro.vendor.product.cpu.abilist64
adb shell getprop ro.vendor.product.cpu.abilist # all abi
```
180 changes: 180 additions & 0 deletions docs/document/Modern CSharp/docs/Understanding Bit Operation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Understanding Bit Operation

## Bit Shifting

### Left & Right Shifting

Left shifting moves the whole bit sequence with specific count to left, `0` will fill up the tail and the leading bits are just discarded.

```cs

uint before = 0b_1001_0000_0000_0000_0000_0000_0000_1001;
uint after = before << 4;
Console.WriteLine($"{nameof(before),6}: {before,32:B32}");
Console.WriteLine($"{nameof(after),6}: {after:B32}");

// before: 10010000000000000000000000001001
// ^^^^ ^^^^
// discarded move left
// after: 00000000000000000000000010010000
// ^^^^
```

Right shifting does it reversely.
The only difference is, when shifting on *signed* integers, bits would be filled with the sign bit value(`0` for positive, `1` for negative)

```cs
sbyte before = sbyte.MinValue;
sbyte after = (sbyte)(before >> 4);
Console.WriteLine($"{nameof(before),6}: {before:B8}");
Console.WriteLine($"{nameof(after),6}: {after:B8}");

```

> [!NOTE]
> Left & Right Shifting supports only `int`, `uint`, `long`, `ulong`. If you perform shifting on other integer types, the leftoperand is converted as `int`
> [!NOTE]
> If shift count exceeds the bit width or is even negative, the count is determined by
> - if leftoperand is `int` or `uint`: `count = count & 0b_1_1111`
> - if leftoperand is `long` or `ulong`: `count = count & 0b_11_1111`
> [!NOTE]
> Left shifting might discard sign of the number when it's signed
>```cs
>int foo = -0b_0001_0001_0001_0001_0001_0001_0001_0001_01;
>Console.WriteLine(foo.ToString("B32"));
>Console.WriteLine((foo << 1).ToString("B32"));
>Console.WriteLine(int.IsPositive(foo << 1));
>// 10111011101110111011101110111011
>// 01110111011101110111011101110110
>// True
>```
### Unsigned Right Shifting
> [!NOTE]
> `>>>` was supported since C# 11
If you want to make sure that the empty bits are filled with `0` instead of value of the sign when working with the signed integers, use `>>>`!
```cs
int before = int.MinValue;
int after = before >> 2;
int afterUnsigned = before >>> 2; // [!code highlight]
Console.WriteLine($"{nameof(before),-20}: {before:B32}");
Console.WriteLine($"{nameof(after),-20}: {after:B32}");
Console.WriteLine($"{nameof(afterUnsigned),-20}: {afterUnsigned:B32}");
// before : 10000000000000000000000000000000
// after : 11100000000000000000000000000000
// afterUnsigned : 00100000000000000000000000000000 // [!code highlight]
```
> [!NOTE]
> Before `>>>` was added, you had to perform casting to achieve the same
>```cs
>int afterUnsigned = unchecked((int)((uint)before >> 2));
>```
## Bitwise NOT
Reverse value of each bit
```cs
uint before = 0b_0100010;
uint after = ~before;
Console.WriteLine($"{nameof(before),6}: {before,32:B32}");
Console.WriteLine($"{nameof(after),6}: {after:B}");
// before: 00000000000000000000000000100010
// after: 11111111111111111111111111011101
```
## Bitwise OR & AND & XOR

- bitwise OR `|`: returns `1` for each bit as long as one of the two is `1`, else `0`
- bitwise AND `&`: returns `1` for each bit as long as all of the two is `1`, else `0`
- bitwise XOR `^`: returns `1` if the two bits are different, `0` when identical


## Bitwise on Enum

Enum can be flags when the type is marked with `FlagsAttribute` and ordinary enum members are powers of 2(members represent the `All` or `None` are exceptional)

```cs
[Flags]
enum Foo
{
None = 0b0000,
Bar = 0b0001,
Baz = 0b0010,
Qux = 0b0100,
Goo = 0b1000,
All = 0b1111
}
// powers can be easily done by left shifting
[Flags]
enum Foo
{
None = 0,
Bar = 1,
Baz = 1 << 1,
Qux = 1 << 2,
Goo = 1 << 3,
All = ~(~0 << 4)
}
```

## Bit Mask

Bit mask is a common pattern that works like a filter to include or exclude or test bits.
The mask can refer to a integer represented as binary, a sequence of integers or a matrix of integers. The classical usage is a singular number.

### Is Bit Set

A common usage of mask is check whether specific bit **is set**

- when a bit is `1` meaning that it **is set**
- when a bit is `0` meaning that it **is cleared**

A mask is a predefined number with special layout designated to solve specific problem.
The following example shows how a mask is generated for the purpose.

`1` is shifted left to the position we would like to compare, and a bitwise AND is performed.
Only the position matters since other bits are all `0` in the mask.
So only when the bit on the position is set can the operation returns non-zero value.

```cs
uint number = 0b_0101;
int position = 2;
int mask = 1 << position; // generate a special number 0100
bool positionIsSet = (number & mask) != 0;
```

This is the particular same case as how we tell whether a union of enum contains a enum flag.
Since each enum member has **only one bit set**, the union in the following example has two bits set, only when the set bit from the flag being checked overlaps with any bit of the union can it evaluate to non-zero.
And in fact the operation `(union & flag)` should be equal to the flag itself.

> [!WARNING]
> You have to make sure the enum member ot integer to be checked is a valid member or it may evaluate to unexpected value.
```cs
Foo foo = Foo.Bar | Foo.Qux;
_ = (foo & Foo.Qux) != 0; // True
_ = (foo & Foo.Qux) == Foo.Qux; // True
_ = (foo & Foo.Goo) != 0; // False
_ = (foo & Foo.Goo) == Foo.Goo; // False
[Flags]
enum Foo
{
None = 0,
Bar = 1,
Baz = 1 << 1,
Qux = 1 << 2,
Goo = 1 << 3,
All = ~(~0 << 4)
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The second syntax in composite formatting is a optional integer for the interpol
```cs
string.Format("{0,20}", 123);
// 123
string.Format("{0,-20}", 123);
string.Format("{0,-20:G}", 123);
// 123 ^ ends here
```

Expand Down Expand Up @@ -94,7 +94,54 @@ Composite formatting supports a dedicated syntax to represent any numeric format
> [!NOTE]
> See [standard TimeSpan format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings#the-general-long-g-format-specifier) and [Arbitrary TimeSpan format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings)
## How to Support a Custom Format
### Enum Format

Enum formatting is handled by `Enum.ToString` static methods. They're implicitly called as if they're intrinsic.

There's two scenarios of enum formatting
- singular value
A valid enum value as integer can be directly evaluated as the enum name.
More specifically, the format is **G**eneral when there's no format specified.
If an integer is not a valid value for the enum, compiler does not yell but the default evaluation for it will be the number itself
```cs
Console.WriteLine(((DayOfWeek)0).ToString()); // Sunday
Console.WriteLine(((DayOfWeek)0).ToString("G")); // Sunday
Console.WriteLine(((DayOfWeek)7).ToString()); // 7, which is not a member of the enum
```
However, `Enum.ToString` supports `F` format for a invalid value of enum that can be formatted as a union
> [!NOTE]
> Respectively you can use `D` and `X` to enforce format a enum or enum union to be decimal numeric and hexadecimal when the enum is a valid flag
```cs
Console.WriteLine(((DayOfWeek)7).ToString("F")); // Monday, Saturday
Console.WriteLine((Foo.Bar | Foo.Baz).ToString("F")); // Bar, Baz
enum Foo
{
None = 0b0000,
Bar = 0b0001,
Baz = 0b0010,
Qux = 0b0100,
Goo = 0b1000,
All = 0b1111
}
```
- bitwise or
As long as the enum was marked with `FlagAttribute` and all member values are in a powered order, the bitwise or result of any distinct combination can be formatted as the names of enum member separated by comma.
```cs
var foo = (Foo.Bar | Foo.Baz | Foo.Bar).ToString(); // Bar, Baz
[Flags]
enum Foo
{
None = 0b0000,
Bar = 0b0001,
Baz = 0b0010,
Qux = 0b0100,
Goo = 0b1000,
All = 0b1111
}
```


## Custom Formatting

Before we implement a custom process for our format, we have to understand the common interfaces for formatting.

Expand Down Expand Up @@ -320,3 +367,33 @@ if (s == null) // if ICustomFormatter.Format returns null // [!code highlight]

> [!NOTE]
> `ISpanFormattable` is a more advance topic since .NET 6.

## Formatting in Interpolated String

### Use Culture

Interpolated strings are always formatted using `CultureInfo.CurrentCulture` by default.

- .NET 5 and earlier: `FormattableString` can be used as a wrapper of a interpolated string and use `FormattableString.ToString(IFormatProvider)` to format it by certain culture.

```cs
FormattableString str = $"I am a syntax sugar for {"FormattableString"}";
_ = str.ToString(CultureInfo.CreateSpecificCulture("en-US"));
```

- since .NET 6: using `string.Create(IFormatProvider? provider, ref DefaultInterpolatedStringHandler handler)` is a more performance solution.
The syntax shorthand is kind of extreme, you don't even have to specify `ref`, compiler will do it for you.

```cs
_ = string.Create(
CultureInfo.CreateSpecificCulture("en-US"),
$"I am a syntax sugar for {"DefaultInterpolatedStringHandler"}"
);
```

### Interpolated String Handler

<!--TODO:expalin how a Interpolated string handler work, what is a handler pattern-->
> [!NOTE]
> See [Interpolated String Handler Pattern](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/improved-interpolated-strings#the-handler-pattern)
> and [Custom Interpolated String Handler](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/performance/interpolated-string-handler)
3 changes: 2 additions & 1 deletion docs/document/PowerShell/docs/Item Manipulation/Path.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
## Part of Path
- `-Path(0, pv)`: get parent path as `PathInfo`
- `-Path(0, pv)`: get parent path as `string`
```ps1
Split-Path ([System.IO.Path]::GetTempFileName()) # C:\Users\username\AppData\Local\Temp
```
Expand Down Expand Up @@ -92,6 +92,7 @@
```ps1
Join-Path -Path foo -ChildPath foo -AdditionalChildPath foo, foo, foo # this is how it work formally
Join-Path foo foo foo foo foo # this is how you could use it in daily life
# foo\foo\foo\foo\foo
```
- `-Resolve(switch)`: resolve( and validate) the path and join them, supports wildcard to join multiple matches at one time
```ps1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Scoped Options

Scoped options are constrains to describe the state of a **item**, only specific to items alive during a session like aliases, functions and variables.

Item cmdlets may have `-Options` parameter but there won't have completion for it unless you're operating on a session state item.

> [!NOTE]
> See [ScopedItemOptions](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.scopeditemoptions?view=powershellsdk-7.4.0&viewFallbackFrom=powershellsdk-7.0.0)

0 comments on commit 97f1e4e

Please sign in to comment.